]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
Implement printing out of expressions so that they can be output to the lease databas...
authorTed Lemon <source@isc.org>
Wed, 22 Sep 1999 01:45:57 +0000 (01:45 +0000)
committerTed Lemon <source@isc.org>
Wed, 22 Sep 1999 01:45:57 +0000 (01:45 +0000)
common/execute.c
common/print.c
common/tree.c
includes/dhcpd.h
server/db.c

index 06d4efd606f8953847a91d4888909b9bc7b89e2b..87df6cb4df4082c55e439cbedb22272fc383536e 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: execute.c,v 1.18 1999/09/15 17:22:52 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: execute.c,v 1.19 1999/09/22 01:45:49 mellon Exp $ Copyright (c) 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -308,3 +308,151 @@ int executable_statement_dereference (ptr, name)
        *ptr = (struct executable_statement *)0;
        return 1;
 }
+
+void write_statements (file, statements, indent)
+       FILE *file;
+       struct executable_statement *statements;
+       int indent;
+{
+       struct executable_statement *r, *x;
+       int result;
+       int status;
+       char *s, *t, *dot;
+       int col;
+
+       if (!statements)
+               return;
+
+       for (r = statements; r; r = r -> next) {
+               switch (r -> op) {
+                     case statements_statement:
+                       write_statements (file, r -> data.statements, indent);
+                       break;
+
+                     case on_statement:
+                       switch (r -> data.on.evtype) {
+                             case expiry:
+                               s = "expiry";
+                               break;
+                             case commit:
+                               s = "commit";
+                               break;
+                             case release:
+                               s = "release";
+                               break;
+                             default:
+                               log_fatal ("unknown event type %d %s",
+                                          r -> data.on.evtype,
+                                          "in on statement.");
+                       }
+                       indent_spaces (file, indent);
+                       fprintf (file, "on %s {", s);
+                       write_statements (file, r -> data.on.statements,
+                                         indent + 2);
+                       indent_spaces (file, indent);
+                       fprintf (file, "}");
+                       break;
+
+                     case if_statement:
+                       indent_spaces (file, indent);
+                       fprintf (file, "if ");
+                       x = r;
+                       col = write_expression (file,
+                                               x -> data.ie.expr,
+                                               indent + 3, indent + 3);
+                     else_if:
+                       token_print_indent (file, col, indent, " ", "", "{");
+                       write_statements (file, x -> data.ie.true, indent + 2);
+                       if (x -> data.ie.false &&
+                           x -> data.ie.false -> op == if_statement &&
+                           !x -> data.ie.false -> next) {
+                               indent_spaces (file, indent);
+                               fprintf (file, "} elsif ");
+                               x = x -> data.ie.false;
+                               col = write_expression (file,
+                                                       x -> data.ie.expr,
+                                                       indent + 6,
+                                                       indent + 6);
+                               goto else_if;
+                       }
+                       if (x -> data.ie.false) {
+                               indent_spaces (file, indent);
+                               fprintf (file, "} else {");
+                               write_statements (file, x -> data.ie.false,
+                                                 indent + 2);
+                       }
+                       indent_spaces (file, indent);
+                       fprintf (file, "}");
+                       break;
+
+                     case eval_statement:
+                       indent_spaces (file, indent);
+                       fprintf (file, "eval ");
+                       col = write_expression (file, r -> data.eval,
+                                               indent + 5, indent + 5);
+                       fprintf (file, ";");
+                       break;
+
+                     case add_statement:
+                       indent_spaces (file, indent);
+                       fprintf (file, "add \"%s\"", r -> data.add -> name);
+                       break;
+
+                     case break_statement:
+                       indent_spaces (file, indent);
+                       fprintf (file, "break;");
+                       break;
+
+                     case supersede_option_statement:
+                       s = "supersede";
+                       goto option_statement;
+
+                     case default_option_statement:
+                       s = "default";
+                       goto option_statement;
+
+                     case append_option_statement:
+                       s = "append";
+                       goto option_statement;
+
+                     case prepend_option_statement:
+                       s = "prepend";
+                     option_statement:
+                       /* Note: the reason we don't try to pretty print
+                          the option here is that the format of the option
+                          may change in dhcpd.conf, and then when this
+                          statement was read back, it would cause a syntax
+                          error. */
+                       if (r -> data.option -> option -> universe ==
+                           &dhcp_universe) {
+                               t = (char *)0;
+                               dot = "";
+                       } else {
+                               t = (r -> data.option -> option ->
+                                    universe -> name);
+                               dot = ".";
+                       }
+                       indent_spaces (file, indent);
+                       fprintf (file, "%s %s%s%s = ", s, t, dot,
+                                r -> data.option -> option -> name);
+                       col = (indent + strlen (s) + strlen (t) +
+                              strlen (dot) + strlen (r -> data.option ->
+                                                     option -> name) + 4);
+                       if (r -> data.option -> expression)
+                               write_expression
+                                       (file,
+                                        r -> data.option -> expression,
+                                        col, indent + 8);
+                       else
+                               token_indent_data_string
+                                       (file, col, indent + 8, "", "",
+                                        &r -> data.option -> data);
+                                        
+                       fprintf (file, ";"); /* XXX */
+                       break;
+
+                     default:
+                       log_fatal ("bogus statement type %d\n", r -> op);
+               }
+       }
+}
index 0942df5b84065ee8167f419501ad7b94cd792c29..df5f9335315259924e286737c1aac63f7b9116a9 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: print.c,v 1.23 1999/07/13 18:00:12 mellon Exp $ Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: print.c,v 1.24 1999/09/22 01:45:49 mellon Exp $ Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -520,3 +520,112 @@ void print_expression (name, expr)
        log_info ("%s: %s", name, buf);
 }
 
+int token_print_indent_concat (FILE *file, int col,  int indent, char *prefix, 
+                              char *suffix, ...)
+{
+       va_list list;
+       char *buf;
+       int len;
+       char *s, *t, *u;
+
+       va_start (list, suffix);
+       s = va_arg (list, char *);
+       len = 0;
+       while (s) {
+               len += strlen (s);
+               s = va_arg (list, char *);
+       }
+       va_end (list);
+
+       t = malloc (len + 1);
+       if (!t)
+               log_fatal ("token_print_indent: no memory for copy buffer");
+
+       va_start (list, suffix);
+       s = va_arg (list, char *);
+       u = t;
+       while (s) {
+               len = strlen (s);
+               strcpy (u, s);
+               u += len;
+       }
+       va_end (list);
+       
+       len = token_print_indent (file, col, indent,
+                                 prefix, suffix, t);
+       free (t);
+       return col;
+}
+
+int token_indent_data_string (FILE *file, int col, int indent,
+                             char *prefix, char *suffix,
+                             struct data_string *data)
+{
+       int i;
+       char *buf;
+       char obuf [3];
+
+       /* See if this is just ASCII. */
+       for (i = 0; i < data -> len; i++)
+               if (!isascii (data -> data [i]) ||
+                   !isprint (data -> data [i]))
+                       break;
+
+       /* If we have a purely ASCII string, output it as text. */
+       if (i == data -> len) {
+               char *buf = malloc (data -> len + 3);
+               if (buf) {
+                       buf [0] = '"';
+                       memcpy (buf + 1, data -> data, data -> len);
+                       buf [data -> len + 1] = '"';
+                       buf [data -> len + 2] = 0;
+                       i = token_print_indent (file, col, indent,
+                                               prefix, suffix, buf);
+                       free (buf);
+                       return i;
+               }
+       }
+
+       for (i = 0; i < data -> len; i++) {
+               sprintf (obuf, "%2.2x", data -> data [i]);
+               col = token_print_indent (file, col, indent,
+                                         i == 0 ? prefix : "",
+                                         (i + 1 == data -> len
+                                          ? suffix
+                                          : ""), obuf);
+               if (i + 1 != data -> len)
+                       col = token_print_indent (file, col, indent,
+                                                 prefix, suffix, obuf);
+       }
+       return col;
+}
+
+int token_print_indent (FILE *file, int col, int indent,
+                       char *prefix, char *suffix, char *buf)
+{
+       int len = strlen (buf) + strlen (prefix);
+       if (col + len > 79 && indent + len < 79) {
+               fputc ('\n', file);
+               indent_spaces (file, indent);
+               col = indent;
+       } else if (prefix && *prefix) {
+               fputs (prefix, file);
+               col += strlen (prefix);
+       }
+       fputs (buf, file);
+       col += len;
+       if (col + strlen (suffix) > 79) {
+               fputc ('\n', file);
+               indent_spaces (file, indent);
+               col = indent;
+       }
+       return col;
+}
+
+void indent_spaces (FILE *file, int indent)
+{
+       int i;
+       for (i = 0; i < indent; i++)
+               fputc (' ', file);
+}
+
index 2d4c6dda733996fa73de753f9962342f22df18f3..575fe3fa2c6754cebaf6028717a042676c589e1c 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: tree.c,v 1.48 1999/09/16 01:10:19 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: tree.c,v 1.49 1999/09/22 01:45:49 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -313,14 +313,14 @@ static int do_host_lookup (result, dns)
                        break;
                      case TRY_AGAIN:
                        log_error ("%s: temporary name server failure",
-                             dns -> hostname);
+                                  dns -> hostname);
                        break;
                      case NO_RECOVERY:
                        log_error ("%s: name server failed", dns -> hostname);
                        break;
                      case NO_DATA:
                        log_error ("%s: no A record associated with address",
-                             dns -> hostname);
+                                  dns -> hostname);
                }
 #endif /* !NO_H_ERRNO */
 
@@ -1839,3 +1839,334 @@ enum expression_context op_context (op)
        }
        return context_any;
 }
+
+int write_expression (file, expr, col, indent)
+       FILE *file;
+       struct expression *expr;
+       int col;
+       int indent;
+{
+       struct expression *e;
+       char *s;
+       char obuf [65];
+       int scol;
+       int width;
+
+       switch (expr -> op) {
+             case expr_none:
+               col = token_print_indent (file, col, indent, "", "", "null");
+               break;
+               
+             case expr_check:
+               col = token_print_indent (file, col, indent, "", "", "check");
+               col = token_print_indent_concat (file, col, indent,
+                                                " ", "", "\"",
+                                                expr -> data.check -> name,
+                                                "\"", (char *)0);
+               break;
+
+             case expr_equal:
+               s = "=";
+             binary:
+               col = write_expression (file,
+                                       expr -> data.equal [0], col, indent);
+               col = token_print_indent (file, col, indent, " ", " ", s);
+               col = write_expression (file,
+                                       expr -> data.equal [0], col, indent);
+               break;
+
+             case expr_substring:
+               col = token_print_indent (file, col, indent, "", "",
+                                         "substring");
+               col = token_print_indent (file, col, indent, " ", "", "(");
+               scol = col;
+               col = write_expression (file, expr -> data.substring.expr,
+                                       col, scol);
+               col = token_print_indent (file, col, indent, "", " ", ",");
+               col = write_expression (file, expr -> data.substring.offset,
+                                       col, indent);
+               col = token_print_indent (file, col, scol, "", " ", ",");
+               col = write_expression (file, expr -> data.substring.len,
+                                       col, scol);
+               col = token_print_indent (file, col, indent, "", "", ")");
+               break;
+
+             case expr_suffix:
+               col = token_print_indent (file, col, indent, "", "", "suffix");
+               col = token_print_indent (file, col, indent, " ", "", "(");
+               scol = col;
+               col = write_expression (file, expr -> data.suffix.expr,
+                                       col, scol);
+               col = token_print_indent (file, col, scol, "", " ", ",");
+               col = write_expression (file, expr -> data.suffix.len,
+                                       col, scol);
+               col = token_print_indent (file, col, indent, "", "", ")");
+               break;
+
+             case expr_concat:
+               e = expr;
+               col = token_print_indent (file, col, indent, "", "",
+                                         "concat");
+               col = token_print_indent (file, col, indent, " ", "", "(");
+               scol = col;
+             concat_again:
+               col = write_expression (file, e -> data.concat [0],
+                                       col, scol);
+               col = token_print_indent (file, col, scol, "", " ", ",");
+               if (e -> data.concat [1] -> op == expr_concat) {
+                       e = e -> data.concat [1];
+                       goto concat_again;
+               }
+               col = write_expression (file, e -> data.concat [1],
+                                       col, scol);
+               col = token_print_indent (file, col, indent, "", "", ")");
+               break;
+
+             case expr_host_lookup:
+               col = token_print_indent (file, col, indent, "", "",
+                                         "gethostbyname");
+               col = token_print_indent (file, col, indent, " ", "", "(");
+               col = token_print_indent_concat
+                       (file, col, indent, "", "",
+                        "\"", expr -> data.host_lookup -> hostname, "\"",
+                        (char *)0);
+               col = token_print_indent (file, col, indent, "", "", ")");
+               break;
+
+             case expr_and:
+               s = "and";
+               goto binary;
+
+             case expr_or:
+               s = "or";
+               goto binary;
+
+             case expr_not:
+               col = token_print_indent (file, col, indent, "", " ", "not");
+               col = write_expression (file,
+                                       expr -> data.not, col, indent);
+               break;
+
+             case expr_option:
+               s = "option";
+
+             print_option_name:
+               col = token_print_indent (file, col, indent, "", "", s);
+
+               if (expr -> data.option -> universe != &dhcp_universe) {
+                       col = token_print_indent (file, col, indent,
+                                                 " ", "",
+                                                 (expr -> data.option -> 
+                                                  universe -> name));
+                       col = token_print_indent (file, col, indent, "", "",
+                                                 ".");
+                       col = token_print_indent (file, col, indent, "", "",
+                                                 expr -> data.option -> name);
+               } else {
+                       col = token_print_indent (file, col, indent, " ", "",
+                                                 expr -> data.option -> name);
+               }
+               break;
+
+             case expr_hardware:       
+               col = token_print_indent (file, col, indent, "", "",
+                                         "hardware");
+               break;
+
+             case expr_packet:
+               col = token_print_indent (file, col, indent, "", "",
+                                         "packet");
+               col = token_print_indent (file, col, indent, " ", "", "(");
+               scol = col;
+               col = write_expression (file, expr -> data.packet.offset,
+                                       col, indent);
+               col = token_print_indent (file, col, scol, "", " ", ",");
+               col = write_expression (file, expr -> data.packet.len,
+                                       col, scol);
+               col = token_print_indent (file, col, indent, "", "", ")");
+               break;
+
+             case expr_const_data:
+               col = token_indent_data_string (file, col, indent, "", "",
+                                               &expr -> data.const_data);
+               break;
+
+             case expr_extract_int8:
+               width = 8;
+             extract_int:
+               col = token_print_indent (file, col, indent, "", "",
+                                         "extract-int");
+               col = token_print_indent (file, col, indent, " ", "", "(");
+               scol = col;
+               col = write_expression (file, expr -> data.extract_int,
+                                       col, indent);
+               col = token_print_indent (file, col, scol, "", " ", ",");
+               sprintf (obuf, "%d", width);
+               col = token_print_indent (file, col, scol, " ", "", obuf);
+               col = token_print_indent (file, col, indent, "", "", ")");
+               break;
+
+             case expr_extract_int16:
+               width = 16;
+               goto extract_int;
+
+             case expr_extract_int32:
+               width = 32;
+               goto extract_int;
+
+             case expr_encode_int8:
+               width = 8;
+             encode_int:
+               col = token_print_indent (file, col, indent, "", "",
+                                         "encode-int");
+               col = token_print_indent (file, col, indent, " ", "", "(");
+               scol = col;
+               col = write_expression (file, expr -> data.extract_int,
+                                       col, indent);
+               col = token_print_indent (file, col, scol, "", " ", ",");
+               sprintf (obuf, "%d", width);
+               col = token_print_indent (file, col, scol, " ", "", obuf);
+               col = token_print_indent (file, col, indent, "", "",
+                                         ")");
+               break;
+
+             case expr_encode_int16:
+               width = 16;
+               goto encode_int;
+
+             case expr_encode_int32:
+               width = 32;
+               goto encode_int;
+
+             case expr_const_int:
+               sprintf (obuf, "%lu", expr -> data.const_int);
+               col = token_print_indent (file, col, indent, "", "", obuf);
+               break;
+
+             case expr_exists:
+               s = "exists";
+               goto print_option_name;
+
+             case expr_encapsulate:
+               col = token_print_indent (file, col, indent, "", "",
+                                         "encapsulate");
+               col = token_indent_data_string (file, col, indent, " ", "",
+                                               &expr -> data.encapsulate);
+               break;
+
+             case expr_known:
+               col = token_print_indent (file, col, indent, "", "", "known");
+               break;
+
+             case expr_reverse:
+               col = token_print_indent (file, col, indent, "", "",
+                                         "reverse");
+               col = token_print_indent (file, col, indent, " ", "", "(");
+               scol = col;
+               col = write_expression (file, expr -> data.reverse.width,
+                                       col, scol);
+               col = token_print_indent (file, col, scol, "", " ", ",");
+               col = write_expression (file, expr -> data.reverse.buffer,
+                                       col, scol);
+               col = token_print_indent (file, col, indent, "", "",
+                                         ")");
+               break;
+
+             case expr_leased_address:
+               col = token_print_indent (file, col, indent, "", "",
+                                         "leased-address");
+               break;
+
+             case expr_binary_to_ascii:
+               col = token_print_indent (file, col, indent, "", "",
+                                         "binary-to-ascii");
+               col = token_print_indent (file, col, indent, " ", "",
+                                         "(");
+               scol = col;
+               col = write_expression (file, expr -> data.b2a.base,
+                                       col, scol);
+               col = token_print_indent (file, col, scol, "", " ",
+                                         ",");
+               col = write_expression (file, expr -> data.b2a.width,
+                                       col, scol);
+               col = token_print_indent (file, col, scol, "", " ",
+                                         ",");
+               col = write_expression (file, expr -> data.b2a.seperator,
+                                       col, scol);
+               col = token_print_indent (file, col, scol, "", " ",
+                                         ",");
+               col = write_expression (file, expr -> data.b2a.buffer,
+                                       col, scol);
+               col = token_print_indent (file, col, indent, "", "",
+                                         ")");
+               break;
+
+             case expr_config_option:
+               s = "exists";
+               goto print_option_name;
+
+             case expr_host_decl_name:
+               col = token_print_indent (file, col, indent, "", "",
+                                         "host-decl-name");
+               break;
+
+             case expr_pick_first_value:
+               e = expr;
+               col = token_print_indent (file, col, indent, "", "",
+                                         "concat");
+               col = token_print_indent (file, col, indent, " ", "",
+                                         "(");
+               scol = col;
+             pick_again:
+               col = write_expression (file,
+                                       e -> data.pick_first_value.car,
+                                       col, scol);
+               col = token_print_indent (file, col, scol, "", " ",
+                                         ",");
+               if (e -> data.pick_first_value.cdr -> op ==
+                   expr_pick_first_value) {
+                       e = e -> data.pick_first_value.cdr;
+                       goto pick_again;
+               }
+               col = write_expression (file,
+                                       e -> data.pick_first_value.cdr,
+                                       col, scol);
+               col = token_print_indent (file, col, indent, "", "",
+                                         ")");
+               break;
+
+             case expr_lease_time:
+               col = token_print_indent (file, col, indent, "", "",
+                                         "lease-time");
+               break;
+
+             case expr_dns_update:
+               col = token_print_indent (file, col, indent, "", "",
+                                         "dns-update");
+               col = token_print_indent (file, col, indent, " ", "",
+                                         "(");
+               scol = col;
+               col = write_expression (file, expr -> data.dns_update.type,
+                                       col, scol);
+               col = token_print_indent (file, col, scol, "", " ",
+                                         ",");
+               col = write_expression (file, expr -> data.dns_update.expr1,
+                                       col, scol);
+               col = token_print_indent (file, col, scol, "", " ",
+                                         ",");
+               col = write_expression (file, expr -> data.dns_update.expr2,
+                                       col, scol);
+               col = token_print_indent (file, col, scol, "", " ",
+                                         ",");
+               col = write_expression (file, expr -> data.dns_update.ttl,
+                                       col, scol);
+               col = token_print_indent (file, col, indent, "", "",
+                                         ")");
+               break;
+
+             default:
+               log_fatal ("invalid expression type in print_expression: %d",
+                          expr -> op);
+       }
+       return col;
+}
index e32ca9adfd5f2f503628e4eed945abdeef6937bd..d7fffefbdd7171f922e618fe60e7b5c2a10962ea 100644 (file)
@@ -1010,6 +1010,7 @@ int is_data_expression PROTO ((struct expression *));
 int is_numeric_expression PROTO ((struct expression *));
 int op_precedence PROTO ((enum expr_op, enum expr_op));
 enum expression_context op_context PROTO ((enum expr_op));
+int write_expression (FILE *, struct expression *, int, int);
 
 /* dhcp.c */
 extern int outstanding_pings;
@@ -1148,6 +1149,8 @@ int executable_statement_reference PROTO ((struct executable_statement **,
                                           char *));
 int executable_statement_dereference PROTO ((struct executable_statement **,
                                             char *));
+void write_statements (FILE *, struct executable_statement *, int);
+
 int packet_allocate PROTO ((struct packet **, char *));
 int packet_reference PROTO ((struct packet **, struct packet *, char *));
 int packet_dereference PROTO ((struct packet **, char *));
@@ -1165,6 +1168,11 @@ char *print_dotted_quads PROTO ((int, u_int8_t *));
 char *print_dec_1 PROTO ((int));
 char *print_dec_2 PROTO ((int));
 void print_expression PROTO ((char *, struct expression *));
+int token_print_indent_concat (FILE *, int, int, char *, char *, ...);
+int token_indent_data_string (FILE *, int, int, char *, char *,
+                             struct data_string *);
+int token_print_indent (FILE *, int, int, char *, char *, char *);
+void indent_spaces (FILE *, int);
 
 /* socket.c */
 #if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_RECEIVE) \
index 29a015d12f63104b66a2c146a38dcded2786a4b1..21aba8a1094b63f4cc3e32007a4e6e0713f0d132 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: db.c,v 1.27 1999/09/09 23:33:18 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: db.c,v 1.28 1999/09/22 01:45:57 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -156,7 +156,6 @@ int write_lease (lease)
                }
        }
        if (lease -> hostname && db_printable (lease -> hostname)) {
-               errno = 0;
                errno = 0;
                fprintf (db_file, "\n\thostname \"%s\";",
                         lease -> hostname);
@@ -164,6 +163,24 @@ int write_lease (lease)
                        ++errors;
                }
        }
+       if (lease -> on_expiry) {
+               errno = 0;
+               fprintf (db_file, "\n\ton expiry {");
+               if (errno)
+                       ++errors;
+               write_statements (db_file, lease -> on_expiry, 10);
+               /* XXX */
+               fprintf (db_file, "\n\t}");
+       }
+       if (lease -> on_release) {
+               errno = 0;
+               fprintf (db_file, "\n\ton release {");
+               if (errno)
+                       ++errors;
+               write_statements (db_file, lease -> on_release, 10);
+               /* XXX */
+               fprintf (db_file, "\n\t}");
+       }
        errno = 0;
        fputs ("\n}\n", db_file);
        if (errno) {