common/print.c

Go to the documentation of this file.
00001 /* print.c
00002 
00003    Turn data structures into printable text. */
00004 
00005 /*
00006  * Copyright (c) 2009-2014 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
00008  * Copyright (c) 1995-2003 by Internet Software Consortium
00009  *
00010  * Permission to use, copy, modify, and distribute this software for any
00011  * purpose with or without fee is hereby granted, provided that the above
00012  * copyright notice and this permission notice appear in all copies.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00015  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00016  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00017  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00018  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00019  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00020  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00021  *
00022  *   Internet Systems Consortium, Inc.
00023  *   950 Charter Street
00024  *   Redwood City, CA 94063
00025  *   <info@isc.org>
00026  *   https://www.isc.org/
00027  *
00028  */
00029 
00030 #include "dhcpd.h"
00031 
00032 int db_time_format = DEFAULT_TIME_FORMAT;
00033 
00034 char *quotify_string (const char *s, const char *file, int line)
00035 {
00036         unsigned len = 0;
00037         const char *sp;
00038         char *buf, *nsp;
00039 
00040         for (sp = s; sp && *sp; sp++) {
00041                 if (*sp == ' ')
00042                         len++;
00043                 else if (!isascii ((int)*sp) || !isprint ((int)*sp))
00044                         len += 4;
00045                 else if (*sp == '"' || *sp == '\\')
00046                         len += 2;
00047                 else
00048                         len++;
00049         }
00050 
00051         buf = dmalloc (len + 1, file, line);
00052         if (buf) {
00053                 nsp = buf;
00054                 for (sp = s; sp && *sp; sp++) {
00055                         if (*sp == ' ')
00056                                 *nsp++ = ' ';
00057                         else if (!isascii ((int)*sp) || !isprint ((int)*sp)) {
00058                                 sprintf (nsp, "\\%03o",
00059                                          *(const unsigned char *)sp);
00060                                 nsp += 4;
00061                         } else if (*sp == '"' || *sp == '\\') {
00062                                 *nsp++ = '\\';
00063                                 *nsp++ = *sp;
00064                         } else
00065                                 *nsp++ = *sp;
00066                 }
00067                 *nsp++ = 0;
00068         }
00069         return buf;
00070 }
00071 
00072 char *quotify_buf (const unsigned char *s, unsigned len,
00073                    const char *file, int line)
00074 {
00075         unsigned nulen = 0;
00076         char *buf, *nsp;
00077         int i;
00078 
00079         for (i = 0; i < len; i++) {
00080                 if (s [i] == ' ')
00081                         nulen++;
00082                 else if (!isascii (s [i]) || !isprint (s [i]))
00083                         nulen += 4;
00084                 else if (s [i] == '"' || s [i] == '\\')
00085                         nulen += 2;
00086                 else
00087                         nulen++;
00088         }
00089 
00090         buf = dmalloc (nulen + 1, MDL);
00091         if (buf) {
00092                 nsp = buf;
00093                 for (i = 0; i < len; i++) {
00094                         if (s [i] == ' ')
00095                                 *nsp++ = ' ';
00096                         else if (!isascii (s [i]) || !isprint (s [i])) {
00097                                 sprintf (nsp, "\\%03o", s [i]);
00098                                 nsp += 4;
00099                         } else if (s [i] == '"' || s [i] == '\\') {
00100                                 *nsp++ = '\\';
00101                                 *nsp++ = s [i];
00102                         } else
00103                                 *nsp++ = s [i];
00104                 }
00105                 *nsp++ = 0;
00106         }
00107         return buf;
00108 }
00109 
00110 char *print_base64 (const unsigned char *buf, unsigned len,
00111                     const char *file, int line)
00112 {
00113         char *s, *b;
00114         unsigned bl;
00115         int i;
00116         unsigned val, extra;
00117         static char to64 [] =
00118            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00119 
00120         bl = ((len * 4 + 2) / 3) + 1;
00121         b = dmalloc (bl + 1, file, line);
00122         if (!b)
00123                 return (char *)0;
00124         
00125         i = 0;
00126         s = b;
00127         while (i != len) {
00128                 val = buf [i++];
00129                 extra = val & 3;
00130                 val = val >> 2;
00131                 *s++ = to64 [val];
00132                 if (i == len) {
00133                         *s++ = to64 [extra << 4];
00134                         *s++ = '=';
00135                         break;
00136                 }
00137                 val = (extra << 8) + buf [i++];
00138                 extra = val & 15;
00139                 val = val >> 4;
00140                 *s++ = to64 [val];
00141                 if (i == len) {
00142                         *s++ = to64 [extra << 2];
00143                         *s++ = '=';
00144                         break;
00145                 }
00146                 val = (extra << 8) + buf [i++];
00147                 extra = val & 0x3f;
00148                 val = val >> 6;
00149                 *s++ = to64 [val];
00150                 *s++ = to64 [extra];
00151         }
00152         if (!len)
00153                 *s++ = '=';
00154         *s++ = 0;
00155         if (s > b + bl + 1)
00156                 abort ();
00157         return b;
00158 }
00159 
00160 char *print_hw_addr (htype, hlen, data)
00161         const int htype;
00162         const int hlen;
00163         const unsigned char *data;
00164 {
00165         static char habuf [49];
00166         char *s;
00167         int i;
00168 
00169         if (hlen <= 0)
00170                 habuf [0] = 0;
00171         else {
00172                 s = habuf;
00173                 for (i = 0; i < hlen; i++) {
00174                         sprintf (s, "%02x", data [i]);
00175                         s += strlen (s);
00176                         *s++ = ':';
00177                 }
00178                 *--s = 0;
00179         }
00180         return habuf;
00181 }
00182 
00183 void print_lease (lease)
00184         struct lease *lease;
00185 {
00186         struct tm *t;
00187         char tbuf [32];
00188 
00189         log_debug ("  Lease %s",
00190                piaddr (lease -> ip_addr));
00191         
00192         t = gmtime (&lease -> starts);
00193         strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
00194         log_debug ("  start %s", tbuf);
00195         
00196         t = gmtime (&lease -> ends);
00197         strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
00198         log_debug ("  end %s", tbuf);
00199         
00200         if (lease -> hardware_addr.hlen)
00201                 log_debug ("    hardware addr = %s",
00202                            print_hw_addr (lease -> hardware_addr.hbuf [0],
00203                                           lease -> hardware_addr.hlen - 1,
00204                                           &lease -> hardware_addr.hbuf [1]));
00205         log_debug ("  host %s  ",
00206                lease -> host ? lease -> host -> name : "<none>");
00207 }       
00208 
00209 #if defined (DEBUG_PACKET)
00210 void dump_packet_option (struct option_cache *oc,
00211                          struct packet *packet,
00212                          struct lease *lease,
00213                          struct client_state *client,
00214                          struct option_state *in_options,
00215                          struct option_state *cfg_options,
00216                          struct binding_scope **scope,
00217                          struct universe *u, void *foo)
00218 {
00219         const char *name, *dot;
00220         struct data_string ds;
00221         memset (&ds, 0, sizeof ds);
00222 
00223         if (u != &dhcp_universe) {
00224                 name = u -> name;
00225                 dot = ".";
00226         } else {
00227                 name = "";
00228                 dot = "";
00229         }
00230         if (evaluate_option_cache (&ds, packet, lease, client,
00231                                    in_options, cfg_options, scope, oc, MDL)) {
00232                 log_debug ("  option %s%s%s %s;\n",
00233                            name, dot, oc -> option -> name,
00234                            pretty_print_option (oc -> option,
00235                                                 ds.data, ds.len, 1, 1));
00236                 data_string_forget (&ds, MDL);
00237         }
00238 }
00239 
00240 void dump_packet (tp)
00241         struct packet *tp;
00242 {
00243         struct dhcp_packet *tdp = tp -> raw;
00244 
00245         log_debug ("packet length %d", tp -> packet_length);
00246         log_debug ("op = %d  htype = %d  hlen = %d  hops = %d",
00247                tdp -> op, tdp -> htype, tdp -> hlen, tdp -> hops);
00248         log_debug ("xid = %x  secs = %ld  flags = %x",
00249                tdp -> xid, (unsigned long)tdp -> secs, tdp -> flags);
00250         log_debug ("ciaddr = %s", inet_ntoa (tdp -> ciaddr));
00251         log_debug ("yiaddr = %s", inet_ntoa (tdp -> yiaddr));
00252         log_debug ("siaddr = %s", inet_ntoa (tdp -> siaddr));
00253         log_debug ("giaddr = %s", inet_ntoa (tdp -> giaddr));
00254         log_debug ("chaddr = %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
00255                ((unsigned char *)(tdp -> chaddr)) [0],
00256                ((unsigned char *)(tdp -> chaddr)) [1],
00257                ((unsigned char *)(tdp -> chaddr)) [2],
00258                ((unsigned char *)(tdp -> chaddr)) [3],
00259                ((unsigned char *)(tdp -> chaddr)) [4],
00260                ((unsigned char *)(tdp -> chaddr)) [5]);
00261         log_debug ("filename = %s", tdp -> file);
00262         log_debug ("server_name = %s", tdp -> sname);
00263         if (tp -> options_valid) {
00264                 int i;
00265 
00266                 for (i = 0; i < tp -> options -> universe_count; i++) {
00267                         if (tp -> options -> universes [i]) {
00268                                 option_space_foreach (tp, (struct lease *)0,
00269                                                       (struct client_state *)0,
00270                                                       (struct option_state *)0,
00271                                                       tp -> options,
00272                                                       &global_scope,
00273                                                       universes [i], 0,
00274                                                       dump_packet_option);
00275                         }
00276                 }
00277         }
00278         log_debug ("%s", "");
00279 }
00280 #endif
00281 
00282 void dump_raw (buf, len)
00283         const unsigned char *buf;
00284         unsigned len;
00285 {
00286         int i;
00287         char lbuf [80];
00288         int lbix = 0;
00289 
00290 /*
00291           1         2         3         4         5         6         7
00292 01234567890123456789012345678901234567890123456789012345678901234567890123
00293 280: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   .................  
00294 */
00295 
00296         memset(lbuf, ' ', 79);
00297         lbuf [79] = 0;
00298 
00299         for (i = 0; i < len; i++) {
00300                 if ((i & 15) == 0) {
00301                   if (lbix) {
00302                         lbuf[53]=' ';
00303                         lbuf[54]=' ';
00304                         lbuf[55]=' ';
00305                         lbuf[73]='\0';
00306                         log_info ("%s", lbuf);
00307                   }
00308                   memset(lbuf, ' ', 79);
00309                   lbuf [79] = 0;
00310                   sprintf (lbuf, "%03x:", i);
00311                   lbix = 4;
00312                 } else if ((i & 7) == 0)
00313                         lbuf [lbix++] = ' ';
00314 
00315                 if(isprint(buf[i])) {
00316                   lbuf[56+(i%16)]=buf[i];
00317                 } else {
00318                   lbuf[56+(i%16)]='.';
00319                 }
00320 
00321                 sprintf (&lbuf [lbix], " %02x", buf [i]);
00322                 lbix += 3;
00323                 lbuf[lbix]=' ';
00324 
00325         }
00326         lbuf[53]=' ';
00327         lbuf[54]=' ';
00328         lbuf[55]=' ';
00329         lbuf[73]='\0';
00330         log_info ("%s", lbuf);
00331 }
00332 
00333 void hash_dump (table)
00334         struct hash_table *table;
00335 {
00336         int i;
00337         struct hash_bucket *bp;
00338 
00339         if (!table)
00340                 return;
00341 
00342         for (i = 0; i < table -> hash_count; i++) {
00343                 if (!table -> buckets [i])
00344                         continue;
00345                 log_info ("hash bucket %d:", i);
00346                 for (bp = table -> buckets [i]; bp; bp = bp -> next) {
00347                         if (bp -> len)
00348                                 dump_raw (bp -> name, bp -> len);
00349                         else
00350                                 log_info ("%s", (const char *)bp -> name);
00351                 }
00352         }
00353 }
00354 
00355 /*
00356  * print a string as hex.  This only outputs
00357  * colon separated hex list no matter what
00358  * the input looks like.  See print_hex
00359  * for a function that prints either cshl
00360  * or a string if all bytes are printible
00361  * It only uses limit characters from buf
00362  * and doesn't do anything if buf == NULL
00363  *
00364  * len - length of data
00365  * data - input data
00366  * limit - length of buf to use
00367  * buf - output buffer
00368  */
00369 void print_hex_only (len, data, limit, buf)
00370         unsigned len;
00371         const u_int8_t *data;
00372         unsigned limit;
00373         char *buf;
00374 {
00375         unsigned i;
00376 
00377         if ((buf == NULL) || (limit < 3))
00378                 return;
00379 
00380         for (i = 0; (i < limit / 3) && (i < len); i++) {
00381                 sprintf(&buf[i*3], "%02x:", data[i]);
00382         }
00383         buf[(i * 3) - 1] = 0;
00384         return;
00385 }
00386 
00387 /*
00388  * print a string as either text if all the characters
00389  * are printable or colon separated hex if they aren't
00390  *
00391  * len - length of data
00392  * data - input data
00393  * limit - length of buf to use
00394  * buf - output buffer
00395  */
00396 void print_hex_or_string (len, data, limit, buf)
00397         unsigned len;
00398         const u_int8_t *data;
00399         unsigned limit;
00400         char *buf;
00401 {
00402         unsigned i;
00403         if ((buf == NULL) || (limit < 3))
00404                 return;
00405 
00406         for (i = 0; (i < (limit - 3)) && (i < len); i++) {
00407                 if (!isascii(data[i]) || !isprint(data[i])) {
00408                         print_hex_only(len, data, limit, buf);
00409                         return;
00410                 }
00411         }
00412 
00413         buf[0] = '"';
00414         i = len;
00415         if (i > (limit - 3))
00416                 i = limit - 3;
00417         memcpy(&buf[1], data, i);
00418         buf[i + 1] = '"';
00419         buf[i + 2] = 0;
00420         return;
00421 }
00422 
00423 /*
00424  * print a string as either hex or text
00425  * using static buffers to hold the output
00426  * 
00427  * len - length of data
00428  * data - input data
00429  * limit - length of buf
00430  * buf_num - the output buffer to use
00431  */
00432 #define HBLEN 1024
00433 char *print_hex(len, data, limit, buf_num)
00434         unsigned len;
00435         const u_int8_t *data;
00436         unsigned limit;
00437         unsigned buf_num;
00438 {
00439         static char hex_buf_1[HBLEN + 1];
00440         static char hex_buf_2[HBLEN + 1];
00441         static char hex_buf_3[HBLEN + 1];
00442         char *hex_buf;
00443 
00444         switch(buf_num) {
00445           case 0:
00446                 hex_buf = hex_buf_1;
00447                 if (limit >= sizeof(hex_buf_1))
00448                         limit = sizeof(hex_buf_1);
00449                 break;
00450           case 1:
00451                 hex_buf = hex_buf_2;
00452                 if (limit >= sizeof(hex_buf_2))
00453                         limit = sizeof(hex_buf_2);
00454                 break;
00455           case 2:
00456                 hex_buf = hex_buf_3;
00457                 if (limit >= sizeof(hex_buf_3))
00458                         limit = sizeof(hex_buf_3);
00459                 break;
00460           default:
00461                 return(NULL);
00462         }
00463 
00464         print_hex_or_string(len, data, limit, hex_buf);
00465         return(hex_buf);
00466 }
00467 
00468 #define DQLEN   80
00469 
00470 char *print_dotted_quads (len, data)
00471         unsigned len;
00472         const u_int8_t *data;
00473 {
00474         static char dq_buf [DQLEN + 1];
00475         int i;
00476         char *s;
00477 
00478         s = &dq_buf [0];
00479         
00480         i = 0;
00481 
00482         /* %Audit% Loop bounds checks to 21 bytes. %2004.06.17,Safe%
00483          * The sprintf can't exceed 18 bytes, and since the loop enforces
00484          * 21 bytes of space per iteration at no time can we exit the
00485          * loop without at least 3 bytes spare.
00486          */
00487         do {
00488                 sprintf (s, "%u.%u.%u.%u, ",
00489                          data [i], data [i + 1], data [i + 2], data [i + 3]);
00490                 s += strlen (s);
00491                 i += 4;
00492         } while ((s - &dq_buf [0] > DQLEN - 21) &&
00493                  i + 3 < len);
00494         if (i == len)
00495                 s [-2] = 0;
00496         else
00497                 strcpy (s, "...");
00498         return dq_buf;
00499 }
00500 
00501 char *print_dec_1 (val)
00502         unsigned long val;
00503 {
00504         static char vbuf [32];
00505         sprintf (vbuf, "%lu", val);
00506         return vbuf;
00507 }
00508 
00509 char *print_dec_2 (val)
00510         unsigned long val;
00511 {
00512         static char vbuf [32];
00513         sprintf (vbuf, "%lu", val);
00514         return vbuf;
00515 }
00516 
00517 static unsigned print_subexpression (struct expression *, char *, unsigned);
00518 
00519 static unsigned print_subexpression (expr, buf, len)
00520         struct expression *expr;
00521         char *buf;
00522         unsigned len;
00523 {
00524         unsigned rv, left;
00525         const char *s;
00526 
00527         switch (expr -> op) {
00528               case expr_none:
00529                 if (len > 3) {
00530                         strcpy (buf, "nil");
00531                         return 3;
00532                 }
00533                 break;
00534                   
00535               case expr_match:
00536                 if (len > 7) {
00537                         strcpy (buf, "(match)");
00538                         return 7;
00539                 }
00540                 break;
00541 
00542               case expr_check:
00543                 rv = 10 + strlen (expr -> data.check -> name);
00544                 if (len > rv) {
00545                         sprintf (buf, "(check %s)",
00546                                  expr -> data.check -> name);
00547                         return rv;
00548                 }
00549                 break;
00550 
00551               case expr_equal:
00552                 if (len > 6) {
00553                         rv = 4;
00554                         strcpy (buf, "(eq ");
00555                         rv += print_subexpression (expr -> data.equal [0],
00556                                                    buf + rv, len - rv - 2);
00557                         buf [rv++] = ' ';
00558                         rv += print_subexpression (expr -> data.equal [1],
00559                                                    buf + rv, len - rv - 1);
00560                         buf [rv++] = ')';
00561                         buf [rv] = 0;
00562                         return rv;
00563                 }
00564                 break;
00565 
00566               case expr_not_equal:
00567                 if (len > 7) {
00568                         rv = 5;
00569                         strcpy (buf, "(neq ");
00570                         rv += print_subexpression (expr -> data.equal [0],
00571                                                    buf + rv, len - rv - 2);
00572                         buf [rv++] = ' ';
00573                         rv += print_subexpression (expr -> data.equal [1],
00574                                                    buf + rv, len - rv - 1);
00575                         buf [rv++] = ')';
00576                         buf [rv] = 0;
00577                         return rv;
00578                 }
00579                 break;
00580 
00581               case expr_regex_match:
00582                 if (len > 10) {
00583                         rv = 4;
00584                         strcpy(buf, "(regex ");
00585                         rv += print_subexpression(expr->data.equal[0],
00586                                                   buf + rv, len - rv - 2);
00587                         buf[rv++] = ' ';
00588                         rv += print_subexpression(expr->data.equal[1],
00589                                                   buf + rv, len - rv - 1);
00590                         buf[rv++] = ')';
00591                         buf[rv] = 0;
00592                         return rv;
00593                 }
00594                 break;
00595 
00596               case expr_substring:
00597                 if (len > 11) {
00598                         rv = 8;
00599                         strcpy (buf, "(substr ");
00600                         rv += print_subexpression (expr -> data.substring.expr,
00601                                                    buf + rv, len - rv - 3);
00602                         buf [rv++] = ' ';
00603                         rv += print_subexpression
00604                                 (expr -> data.substring.offset,
00605                                  buf + rv, len - rv - 2);
00606                         buf [rv++] = ' ';
00607                         rv += print_subexpression (expr -> data.substring.len,
00608                                                    buf + rv, len - rv - 1);
00609                         buf [rv++] = ')';
00610                         buf [rv] = 0;
00611                         return rv;
00612                 }
00613                 break;
00614 
00615               case expr_suffix:
00616                 if (len > 10) {
00617                         rv = 8;
00618                         strcpy (buf, "(suffix ");
00619                         rv += print_subexpression (expr -> data.suffix.expr,
00620                                                    buf + rv, len - rv - 2);
00621                         if (len > rv)
00622                                 buf [rv++] = ' ';
00623                         rv += print_subexpression (expr -> data.suffix.len,
00624                                                    buf + rv, len - rv - 1);
00625                         if (len > rv)
00626                                 buf [rv++] = ')';
00627                         buf [rv] = 0;
00628                         return rv;
00629                 }
00630                 break;
00631 
00632               case expr_lcase:
00633                 if (len > 9) {
00634                         rv = 7;
00635                         strcpy(buf, "(lcase ");
00636                         rv += print_subexpression(expr->data.lcase,
00637                                                   buf + rv, len - rv - 1);
00638                         buf[rv++] = ')';
00639                         buf[rv] = 0;
00640                         return rv;
00641                 }
00642                 break;
00643 
00644               case expr_ucase:
00645                 if (len > 9) {
00646                         rv = 7;
00647                         strcpy(buf, "(ucase ");
00648                         rv += print_subexpression(expr->data.ucase,
00649                                                   buf + rv, len - rv - 1);
00650                         buf[rv++] = ')';
00651                         buf[rv] = 0;
00652                         return rv;
00653                 }
00654                 break;
00655 
00656               case expr_concat:
00657                 if (len > 10) {
00658                         rv = 8;
00659                         strcpy (buf, "(concat ");
00660                         rv += print_subexpression (expr -> data.concat [0],
00661                                                    buf + rv, len - rv - 2);
00662                         buf [rv++] = ' ';
00663                         rv += print_subexpression (expr -> data.concat [1],
00664                                                    buf + rv, len - rv - 1);
00665                         buf [rv++] = ')';
00666                         buf [rv] = 0;
00667                         return rv;
00668                 }
00669                 break;
00670 
00671               case expr_pick_first_value:
00672                 if (len > 8) {
00673                         rv = 6;
00674                         strcpy (buf, "(pick1st ");
00675                         rv += print_subexpression
00676                                 (expr -> data.pick_first_value.car,
00677                                  buf + rv, len - rv - 2);
00678                         buf [rv++] = ' ';
00679                         rv += print_subexpression
00680                                 (expr -> data.pick_first_value.cdr,
00681                                  buf + rv, len - rv - 1);
00682                         buf [rv++] = ')';
00683                         buf [rv] = 0;
00684                         return rv;
00685                 }
00686                 break;
00687 
00688               case expr_host_lookup:
00689                 rv = 15 + strlen (expr -> data.host_lookup -> hostname);
00690                 if (len > rv) {
00691                         sprintf (buf, "(dns-lookup %s)",
00692                                  expr -> data.host_lookup -> hostname);
00693                         return rv;
00694                 }
00695                 break;
00696 
00697               case expr_and:
00698                 s = "and";
00699               binop:
00700                 rv = strlen (s);
00701                 if (len > rv + 4) {
00702                         buf [0] = '(';
00703                         strcpy (&buf [1], s);
00704                         rv += 1;
00705                         buf [rv++] = ' ';
00706                         rv += print_subexpression (expr -> data.and [0],
00707                                                 buf + rv, len - rv - 2);
00708                         buf [rv++] = ' ';
00709                         rv += print_subexpression (expr -> data.and [1],
00710                                                    buf + rv, len - rv - 1);
00711                         buf [rv++] = ')';
00712                         buf [rv] = 0;
00713                         return rv;
00714                 }
00715                 break;
00716 
00717               case expr_or:
00718                 s = "or";
00719                 goto binop;
00720 
00721               case expr_add:
00722                 s = "+";
00723                 goto binop;
00724 
00725               case expr_subtract:
00726                 s = "-";
00727                 goto binop;
00728 
00729               case expr_multiply:
00730                 s = "*";
00731                 goto binop;
00732 
00733               case expr_divide:
00734                 s = "/";
00735                 goto binop;
00736 
00737               case expr_remainder:
00738                 s = "%";
00739                 goto binop;
00740 
00741               case expr_binary_and:
00742                 s = "&";
00743                 goto binop;
00744 
00745               case expr_binary_or:
00746                 s = "|";
00747                 goto binop;
00748 
00749               case expr_binary_xor:
00750                 s = "^";
00751                 goto binop;
00752                 
00753               case expr_not:
00754                 if (len > 6) {
00755                         rv = 5;
00756                         strcpy (buf, "(not ");
00757                         rv += print_subexpression (expr -> data.not,
00758                                                    buf + rv, len - rv - 1);
00759                         buf [rv++] = ')';
00760                         buf [rv] = 0;
00761                         return rv;
00762                 }
00763                 break;
00764 
00765               case expr_config_option:
00766                 s = "cfg-option";
00767                 goto dooption;
00768 
00769               case expr_option:
00770                 s = "option";
00771               dooption:
00772                 rv = strlen (s) + 2 + (strlen (expr -> data.option -> name) +
00773                            strlen (expr -> data.option -> universe -> name));
00774                 if (len > rv) {
00775                         sprintf (buf, "(option %s.%s)",
00776                                  expr -> data.option -> universe -> name,
00777                                  expr -> data.option -> name);
00778                         return rv;
00779                 }
00780                 break;
00781 
00782               case expr_hardware:
00783                 if (len > 10) {
00784                         strcpy (buf, "(hardware)");
00785                         return 10;
00786                 }
00787                 break;
00788 
00789               case expr_packet:
00790                 if (len > 10) {
00791                         rv = 8;
00792                         strcpy (buf, "(substr ");
00793                         rv += print_subexpression (expr -> data.packet.offset,
00794                                                    buf + rv, len - rv - 2);
00795                         buf [rv++] = ' ';
00796                         rv += print_subexpression (expr -> data.packet.len,
00797                                                    buf + rv, len - rv - 1);
00798                         buf [rv++] = ')';
00799                         buf [rv] = 0;
00800                         return rv;
00801                 }
00802                 break;
00803 
00804               case expr_const_data:
00805                 s = print_hex_1 (expr -> data.const_data.len,
00806                                  expr -> data.const_data.data, len);
00807                 rv = strlen (s);
00808                 if (rv >= len)
00809                         rv = len - 1;
00810                 strncpy (buf, s, rv);
00811                 buf [rv] = 0;
00812                 return rv;
00813 
00814               case expr_encapsulate:
00815                 rv = 13;
00816                 strcpy (buf, "(encapsulate ");
00817                 rv += expr -> data.encapsulate.len;
00818                 if (rv + 2 > len)
00819                         rv = len - 2;
00820                 strncpy (buf,
00821                          (const char *)expr -> data.encapsulate.data, rv - 13);
00822                 buf [rv++] = ')';
00823                 buf [rv++] = 0;
00824                 break;
00825 
00826               case expr_extract_int8:
00827                 if (len > 7) {
00828                         rv = 6;
00829                         strcpy (buf, "(int8 ");
00830                         rv += print_subexpression (expr -> data.extract_int,
00831                                                    buf + rv, len - rv - 1);
00832                         buf [rv++] = ')';
00833                         buf [rv] = 0;
00834                         return rv;
00835                 }
00836                 break;
00837 
00838               case expr_extract_int16:
00839                 if (len > 8) {
00840                         rv = 7;
00841                         strcpy (buf, "(int16 ");
00842                         rv += print_subexpression (expr -> data.extract_int,
00843                                                    buf + rv, len - rv - 1);
00844                         buf [rv++] = ')';
00845                         buf [rv] = 0;
00846                         return rv;
00847                 }
00848                 break;
00849 
00850               case expr_extract_int32:
00851                 if (len > 8) {
00852                         rv = 7;
00853                         strcpy (buf, "(int32 ");
00854                         rv += print_subexpression (expr -> data.extract_int,
00855                                                    buf + rv, len - rv - 1);
00856                         buf [rv++] = ')';
00857                         buf [rv] = 0;
00858                         return rv;
00859                 }
00860                 break;
00861 
00862               case expr_encode_int8:
00863                 if (len > 7) {
00864                         rv = 6;
00865                         strcpy (buf, "(to-int8 ");
00866                         rv += print_subexpression (expr -> data.encode_int,
00867                                                    buf + rv, len - rv - 1);
00868                         buf [rv++] = ')';
00869                         buf [rv] = 0;
00870                         return rv;
00871                 }
00872                 break;
00873 
00874               case expr_encode_int16:
00875                 if (len > 8) {
00876                         rv = 7;
00877                         strcpy (buf, "(to-int16 ");
00878                         rv += print_subexpression (expr -> data.encode_int,
00879                                                    buf + rv, len - rv - 1);
00880                         buf [rv++] = ')';
00881                         buf [rv] = 0;
00882                         return rv;
00883                 }
00884                 break;
00885 
00886               case expr_encode_int32:
00887                 if (len > 8) {
00888                         rv = 7;
00889                         strcpy (buf, "(to-int32 ");
00890                         rv += print_subexpression (expr -> data.encode_int,
00891                                                    buf + rv, len - rv - 1);
00892                         buf [rv++] = ')';
00893                         buf [rv] = 0;
00894                         return rv;
00895                 }
00896                 break;
00897 
00898               case expr_const_int:
00899                 s = print_dec_1 (expr -> data.const_int);
00900                 rv = strlen (s);
00901                 if (len > rv) {
00902                         strcpy (buf, s);
00903                         return rv;
00904                 }
00905                 break;
00906 
00907               case expr_exists:
00908                 rv = 10 + (strlen (expr -> data.option -> name) +
00909                            strlen (expr -> data.option -> universe -> name));
00910                 if (len > rv) {
00911                         sprintf (buf, "(exists %s.%s)",
00912                                  expr -> data.option -> universe -> name,
00913                                  expr -> data.option -> name);
00914                         return rv;
00915                 }
00916                 break;
00917 
00918               case expr_variable_exists:
00919                 rv = 10 + strlen (expr -> data.variable);
00920                 if (len > rv) {
00921                         sprintf (buf, "(defined %s)", expr -> data.variable);
00922                         return rv;
00923                 }
00924                 break;
00925 
00926               case expr_variable_reference:
00927                 rv = strlen (expr -> data.variable);
00928                 if (len > rv) {
00929                         sprintf (buf, "%s", expr -> data.variable);
00930                         return rv;
00931                 }
00932                 break;
00933 
00934               case expr_known:
00935                 s = "known";
00936               astring:
00937                 rv = strlen (s);
00938                 if (len > rv) {
00939                         strcpy (buf, s);
00940                         return rv;
00941                 }
00942                 break;
00943 
00944               case expr_leased_address:
00945                 s = "leased-address";
00946                 goto astring;
00947 
00948               case expr_client_state:
00949                 s = "client-state";
00950                 goto astring;
00951 
00952               case expr_host_decl_name:
00953                 s = "host-decl-name";
00954                 goto astring;
00955 
00956               case expr_lease_time:
00957                 s = "lease-time";
00958                 goto astring;
00959 
00960               case expr_static:
00961                 s = "static";
00962                 goto astring;
00963 
00964               case expr_filename:
00965                 s = "filename";
00966                 goto astring;
00967 
00968               case expr_sname:
00969                 s = "server-name";
00970                 goto astring;
00971 
00972               case expr_reverse:
00973                 if (len > 11) {
00974                         rv = 13;
00975                         strcpy (buf, "(reverse ");
00976                         rv += print_subexpression (expr -> data.reverse.width,
00977                                                    buf + rv, len - rv - 2);
00978                         buf [rv++] = ' ';
00979                         rv += print_subexpression (expr -> data.reverse.buffer,
00980                                                    buf + rv, len - rv - 1);
00981                         buf [rv++] = ')';
00982                         buf [rv] = 0;
00983                         return rv;
00984                 }
00985                 break;
00986 
00987               case expr_binary_to_ascii:
00988                 if (len > 5) {
00989                         rv = 9;
00990                         strcpy (buf, "(b2a ");
00991                         rv += print_subexpression (expr -> data.b2a.base,
00992                                                    buf + rv, len - rv - 4);
00993                         buf [rv++] = ' ';
00994                         rv += print_subexpression (expr -> data.b2a.width,
00995                                                    buf + rv, len - rv - 3);
00996                         buf [rv++] = ' ';
00997                         rv += print_subexpression (expr -> data.b2a.separator,
00998                                                    buf + rv, len - rv - 2);
00999                         buf [rv++] = ' ';
01000                         rv += print_subexpression (expr -> data.b2a.buffer,
01001                                                    buf + rv, len - rv - 1);
01002                         buf [rv++] = ')';
01003                         buf [rv] = 0;
01004                         return rv;
01005                 }
01006                 break;
01007 
01008               case expr_dns_transaction:
01009                 rv = 10;
01010                 if (len < rv + 2) {
01011                         buf [0] = '(';
01012                         strcpy (&buf [1], "ns-update ");
01013                         while (len < rv + 2) {
01014                                 rv += print_subexpression
01015                                         (expr -> data.dns_transaction.car,
01016                                          buf + rv, len - rv - 2);
01017                                 buf [rv++] = ' ';
01018                                 expr = expr -> data.dns_transaction.cdr;
01019                         }
01020                         buf [rv - 1] = ')';
01021                         buf [rv] = 0;
01022                         return rv;
01023                 }
01024                 return 0;
01025 
01026               case expr_ns_delete:
01027                 s = "delete";
01028                 left = 4;
01029                 goto dodnsupd;
01030               case expr_ns_exists:
01031                 s = "exists";
01032                 left = 4;
01033                 goto dodnsupd;
01034               case expr_ns_not_exists:
01035                 s = "not_exists";
01036                 left = 4;
01037                 goto dodnsupd;
01038               case expr_ns_add:
01039                 s = "update";
01040                 left = 5;
01041               dodnsupd:
01042                 rv = strlen (s);
01043                 if (len > strlen (s) + 1) {
01044                         buf [0] = '(';
01045                         strcpy (buf + 1, s);
01046                         rv++;
01047                         buf [rv++] = ' ';
01048                         s = print_dec_1 (expr -> data.ns_add.rrclass);
01049                         if (len > rv + strlen (s) + left) {
01050                                 strcpy (&buf [rv], s);
01051                                 rv += strlen (&buf [rv]);
01052                         }
01053                         buf [rv++] = ' ';
01054                         left--;
01055                         s = print_dec_1 (expr -> data.ns_add.rrtype);
01056                         if (len > rv + strlen (s) + left) {
01057                                 strcpy (&buf [rv], s);
01058                                 rv += strlen (&buf [rv]);
01059                         }
01060                         buf [rv++] = ' ';
01061                         left--;
01062                         rv += print_subexpression
01063                                 (expr -> data.ns_add.rrname,
01064                                  buf + rv, len - rv - left);
01065                         buf [rv++] = ' ';
01066                         left--;
01067                         rv += print_subexpression
01068                                 (expr -> data.ns_add.rrdata,
01069                                  buf + rv, len - rv - left);
01070                         buf [rv++] = ' ';
01071                         left--;
01072                         rv += print_subexpression
01073                                 (expr -> data.ns_add.ttl,
01074                                  buf + rv, len - rv - left);
01075                         buf [rv++] = ')';
01076                         buf [rv] = 0;
01077                         return rv;
01078                 }
01079                 break;
01080 
01081               case expr_null:
01082                 if (len > 6) {
01083                         strcpy (buf, "(null)");
01084                         return 6;
01085                 }
01086                 break;
01087               case expr_funcall:
01088                 rv = 12 + strlen (expr -> data.funcall.name);
01089                 if (len > rv + 1) {
01090                         strcpy (buf, "(funcall  ");
01091                         strcpy (buf + 9, expr -> data.funcall.name);
01092                         buf [rv++] = ' ';
01093                         rv += print_subexpression
01094                                 (expr -> data.funcall.arglist, buf + rv,
01095                                  len - rv - 1);
01096                         buf [rv++] = ')';
01097                         buf [rv] = 0;
01098                         return rv;
01099                 }
01100                 break;
01101 
01102               case expr_arg:
01103                 rv = print_subexpression (expr -> data.arg.val, buf, len);
01104                 if (expr -> data.arg.next && rv + 2 < len) {
01105                         buf [rv++] = ' ';
01106                         rv += print_subexpression (expr -> data.arg.next,
01107                                                    buf, len);
01108                         if (rv + 1 < len)
01109                                 buf [rv++] = 0;
01110                         return rv;
01111                 }
01112                 break;
01113 
01114               case expr_function:
01115                 rv = 9;
01116                 if (len > rv + 1) {
01117                         struct string_list *foo;
01118                         strcpy (buf, "(function");
01119                         for (foo = expr -> data.func -> args;
01120                              foo; foo = foo -> next) {
01121                                 if (len > rv + 2 + strlen (foo -> string)) {
01122                                         buf [rv - 1] = ' ';
01123                                         strcpy (&buf [rv], foo -> string);
01124                                         rv += strlen (foo -> string);
01125                                 }
01126                         }
01127                         buf [rv++] = ')';
01128                         buf [rv] = 0;
01129                         return rv;
01130                 }
01131                 break;
01132 
01133               case expr_gethostname:
01134                 if (len > 13) {
01135                         strcpy(buf, "(gethostname)");
01136                         return 13;
01137                 }
01138                 break;
01139 
01140               default:
01141                 log_fatal("Impossible case at %s:%d (undefined expression "
01142                           "%d).", MDL, expr->op);
01143                 break;
01144         }
01145         return 0;
01146 }
01147 
01148 void print_expression (name, expr)
01149         const char *name;
01150         struct expression *expr;
01151 {
01152         char buf [1024];
01153 
01154         print_subexpression (expr, buf, sizeof buf);
01155         log_info ("%s: %s", name, buf);
01156 }
01157 
01158 int token_print_indent_concat (FILE *file, int col,  int indent,
01159                                const char *prefix, 
01160                                const char *suffix, ...)
01161 {
01162         va_list list;
01163         unsigned len;
01164         char *s, *t, *u;
01165 
01166         va_start (list, suffix);
01167         s = va_arg (list, char *);
01168         len = 0;
01169         while (s) {
01170                 len += strlen (s);
01171                 s = va_arg (list, char *);
01172         }
01173         va_end (list);
01174 
01175         t = dmalloc (len + 1, MDL);
01176         if (!t)
01177                 log_fatal ("token_print_indent: no memory for copy buffer");
01178 
01179         va_start (list, suffix);
01180         s = va_arg (list, char *);
01181         u = t;
01182         while (s) {
01183                 len = strlen (s);
01184                 strcpy (u, s);
01185                 u += len;
01186                 s = va_arg (list, char *);
01187         }
01188         va_end (list);
01189         
01190         col = token_print_indent (file, col, indent,
01191                                   prefix, suffix, t);
01192         dfree (t, MDL);
01193         return col;
01194 }
01195 
01196 int token_indent_data_string (FILE *file, int col, int indent,
01197                               const char *prefix, const char *suffix,
01198                               struct data_string *data)
01199 {
01200         int i;
01201         char *buf;
01202         char obuf [3];
01203 
01204         /* See if this is just ASCII. */
01205         for (i = 0; i < data -> len; i++)
01206                 if (!isascii (data -> data [i]) ||
01207                     !isprint (data -> data [i]))
01208                         break;
01209 
01210         /* If we have a purely ASCII string, output it as text. */
01211         if (i == data -> len) {
01212                 buf = dmalloc (data -> len + 3, MDL);
01213                 if (buf) {
01214                         buf [0] = '"';
01215                         memcpy (buf + 1, data -> data, data -> len);
01216                         buf [data -> len + 1] = '"';
01217                         buf [data -> len + 2] = 0;
01218                         i = token_print_indent (file, col, indent,
01219                                                 prefix, suffix, buf);
01220                         dfree (buf, MDL);
01221                         return i;
01222                 }
01223         }
01224 
01225         for (i = 0; i < data -> len; i++) {
01226                 sprintf (obuf, "%2.2x", data -> data [i]);
01227                 col = token_print_indent (file, col, indent,
01228                                           i == 0 ? prefix : "",
01229                                           (i + 1 == data -> len
01230                                            ? suffix
01231                                            : ""), obuf);
01232                 if (i + 1 != data -> len)
01233                         col = token_print_indent (file, col, indent,
01234                                                   prefix, suffix, ":");
01235         }
01236         return col;
01237 }
01238 
01239 int token_print_indent (FILE *file, int col, int indent,
01240                         const char *prefix,
01241                         const char *suffix, const char *buf)
01242 {
01243         int len = 0;
01244         if (prefix != NULL)
01245                 len += strlen (prefix);
01246         if (buf != NULL)
01247                 len += strlen (buf);
01248 
01249         if (col + len > 79) {
01250                 if (indent + len < 79) {
01251                         indent_spaces (file, indent);
01252                         col = indent;
01253                 } else {
01254                         indent_spaces (file, col);
01255                         col = len > 79 ? 0 : 79 - len - 1;
01256                 }
01257         } else if (prefix && *prefix) {
01258                 fputs (prefix, file);
01259                 col += strlen (prefix);
01260         }
01261         if ((buf != NULL) && (*buf != 0)) {
01262                 fputs (buf, file);
01263                 col += strlen(buf);
01264         }
01265         if (suffix && *suffix) {
01266                 if (col + strlen (suffix) > 79) {
01267                         indent_spaces (file, indent);
01268                         col = indent;
01269                 } else {
01270                         fputs (suffix, file);
01271                         col += strlen (suffix);
01272                 }
01273         }
01274         return col;
01275 }
01276 
01277 void indent_spaces (FILE *file, int indent)
01278 {
01279         int i;
01280         fputc ('\n', file);
01281         for (i = 0; i < indent; i++)
01282                 fputc (' ', file);
01283 }
01284 
01285 #if defined (NSUPDATE)
01286 #if defined (DEBUG_DNS_UPDATES)
01287 /*
01288  * direction outbound (messages to the dns server)
01289  *           inbound  (messages from the dns server)
01290  * ddns_cb is the control block associated with the message
01291  * result is the result from the dns code.  For outbound calls
01292  * it is from the call to pass the message to the dns library.
01293  * For inbound calls it is from the event returned by the library.
01294  *
01295  * For outbound messages we print whatever we think is interesting
01296  * from the control block.
01297  * For inbound messages we only print the transaction id pointer
01298  * and the result and expect that the user will match them up as
01299  * necessary.  Note well: the transaction information is opaque to
01300  * us so we simply print the pointer to it.  This should be sufficient
01301  * to match requests and replys in a short sequence but is awkward
01302  * when trying to use it for longer sequences.
01303  */
01304 void
01305 print_dns_status (int direction,
01306                   struct dhcp_ddns_cb *ddns_cb,
01307                   isc_result_t result)
01308 {
01309         char obuf[1024];
01310         char *s = obuf, *end = &obuf[sizeof(obuf)-2];
01311         char *en;
01312         const char *result_str;
01313         char ddns_address[
01314                 sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
01315 
01316         if (direction == DDNS_PRINT_INBOUND) {
01317                 log_info("DDNS reply: id ptr %p, result: %s",
01318                          ddns_cb->transaction, isc_result_totext(result));
01319                 return;
01320         }
01321 
01322         /* 
01323          * To avoid having to figure out if any of the strings
01324          * aren't NULL terminated, just 0 the whole string
01325          */
01326         memset(obuf, 0, 1024);
01327 
01328         en = "DDNS request: id ptr ";
01329         if (s + strlen(en) + 16 < end) {
01330                 sprintf(s, "%s%p", en, ddns_cb->transaction);
01331                 s += strlen(s);
01332         } else {
01333                 goto bailout;
01334         }
01335 
01336         switch (ddns_cb->state) {
01337         case DDNS_STATE_ADD_FW_NXDOMAIN:
01338                 en = " add forward ";
01339                 break;
01340         case DDNS_STATE_ADD_FW_YXDHCID:
01341                 en = " modify forward ";
01342                 break;
01343 
01344         case DDNS_STATE_ADD_PTR:
01345                 en = " add reverse ";
01346                 break;
01347 
01348         case DDNS_STATE_REM_FW_YXDHCID:
01349                 en = " remove forward ";
01350                 break;
01351 
01352         case DDNS_STATE_REM_FW_NXRR:
01353                 en = " remove rrset ";
01354                 break;
01355 
01356         case DDNS_STATE_REM_PTR:
01357                 en = " remove reverse ";
01358                 break;
01359 
01360         case DDNS_STATE_CLEANUP:
01361                 en = " cleanup ";
01362                 break;
01363 
01364         default:
01365                 en = " unknown state ";
01366                 break;
01367         }
01368 
01369         switch (ddns_cb->state) {
01370         case DDNS_STATE_ADD_FW_NXDOMAIN:
01371         case DDNS_STATE_ADD_FW_YXDHCID:
01372         case DDNS_STATE_REM_FW_YXDHCID:
01373         case DDNS_STATE_REM_FW_NXRR:
01374                 strcpy(ddns_address, piaddr(ddns_cb->address));
01375                 if (s + strlen(en) + strlen(ddns_address) +
01376                     ddns_cb->fwd_name.len + 5 < end) {
01377                         sprintf(s, "%s%s for %.*s", en, ddns_address,
01378                                 ddns_cb->fwd_name.len,
01379                                 ddns_cb->fwd_name.data);
01380                         s += strlen(s);
01381                 } else {
01382                         goto bailout;
01383                 }
01384                 break;
01385 
01386         case DDNS_STATE_ADD_PTR:
01387         case DDNS_STATE_REM_PTR:
01388                 if (s + strlen(en) + ddns_cb->fwd_name.len +
01389                     ddns_cb->rev_name.len + 5 < end) {
01390                         sprintf(s, "%s%.*s for %.*s", en,
01391                                 ddns_cb->fwd_name.len,
01392                                 ddns_cb->fwd_name.data,
01393                                 ddns_cb->rev_name.len,
01394                                 ddns_cb->rev_name.data);
01395                         s += strlen(s);
01396                 } else {
01397                         goto bailout;
01398                 }
01399                 break;
01400 
01401         case DDNS_STATE_CLEANUP:
01402         default:
01403                 if (s + strlen(en) < end) {
01404                         sprintf(s, "%s", en);
01405                         s += strlen(s);
01406                 } else {
01407                         goto bailout;
01408                 }
01409                 break;
01410         }
01411 
01412         en = " zone: ";
01413         if (s + strlen(en) + strlen((char *)ddns_cb->zone_name) < end) {
01414                 sprintf(s, "%s%s", en, ddns_cb->zone_name);
01415                 s += strlen(s);
01416         } else {
01417                 goto bailout;
01418         }
01419 
01420         en = " dhcid: ";
01421         if (ddns_cb->dhcid.len > 0) {
01422                 if (s + strlen(en) + ddns_cb->dhcid.len-1 < end) {
01423                         strcpy(s, en);
01424                         s += strlen(s);
01425                         strncpy(s, (char *)ddns_cb->dhcid.data+1,
01426                                 ddns_cb->dhcid.len-1);
01427                         s += strlen(s);
01428                 } else {
01429                         goto bailout;
01430                 }
01431         } else {
01432                 en = " dhcid: <empty>";
01433                 if (s + strlen(en) < end) {
01434                         strcpy(s, en);
01435                         s += strlen(s);
01436                 } else {
01437                         goto bailout;
01438                 }
01439         }
01440 
01441         en = " ttl: ";
01442         if (s + strlen(en) + 10 < end) {
01443                 sprintf(s, "%s%ld", en, ddns_cb->ttl);
01444                 s += strlen(s);
01445         } else {
01446                 goto bailout;
01447         }
01448                 
01449         en = " result: ";
01450         result_str = isc_result_totext(result);
01451         if (s + strlen(en) + strlen(result_str) < end) {
01452                 sprintf(s, "%s%s", en, result_str);
01453                 s += strlen(s);
01454         } else {
01455                 goto bailout;
01456         }
01457 
01458  bailout:
01459         /*
01460          * We either finished building the string or ran out
01461          * of space, print whatever we have in case it is useful
01462          */
01463         log_info("%s", obuf);
01464 
01465         return;
01466 }
01467 #endif
01468 #endif /* NSUPDATE */
01469 
01470 /* Format the given time as "A; # B", where A is the format
01471  * used by the parser, and B is the local time, for humans.
01472  */
01473 const char *
01474 print_time(TIME t)
01475 {
01476         static char buf[sizeof("epoch 9223372036854775807; "
01477                                "# Wed Jun 30 21:49:08 2147483647")];
01478         static char buf1[sizeof("# Wed Jun 30 21:49:08 2147483647")];
01479         time_t since_epoch;
01480         /* The string:         "6 2147483647/12/31 23:59:60;"
01481          * is smaller than the other, used to declare the buffer size, so
01482          * we can use one buffer for both.
01483          */
01484 
01485         if (t == MAX_TIME)
01486                 return "never;";
01487 
01488         if (t < 0)
01489                 return NULL;
01490 
01491         /* For those lucky enough to have a 128-bit time_t, ensure that
01492          * whatever (corrupt) value we're given doesn't exceed the static
01493          * buffer.
01494          */
01495 #if (MAX_TIME > 0x7fffffffffffffff)
01496         if (t > 0x7fffffffffffffff)
01497                 return NULL;
01498 #endif
01499 
01500         if (db_time_format == LOCAL_TIME_FORMAT) {
01501                 since_epoch = mktime(localtime(&t));
01502                 if ((strftime(buf1, sizeof(buf1),
01503                               "# %a %b %d %H:%M:%S %Y",
01504                               localtime(&t)) == 0) ||
01505                     (snprintf(buf, sizeof(buf), "epoch %lu; %s",
01506                               (unsigned long)since_epoch, buf1) >= sizeof(buf)))
01507                         return NULL;
01508 
01509         } else {
01510                 /* No bounds check for the year is necessary - in this case,
01511                  * strftime() will run out of space and assert an error.
01512                  */
01513                 if (strftime(buf, sizeof(buf), "%w %Y/%m/%d %H:%M:%S;",
01514                              gmtime(&t)) == 0)
01515                         return NULL;
01516         }
01517 
01518         return buf;
01519 }

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1