home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume21 / amd / part09 / util.c < prev   
C/C++ Source or Header  |  1990-04-10  |  16KB  |  789 lines

  1. /*
  2.  * $Id: util.c,v 5.1.1.3 90/01/11 17:23:29 jsp Exp Locker: jsp $
  3.  *
  4.  * Copyright (c) 1990 Jan-Simon Pendry
  5.  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
  6.  * Copyright (c) 1990 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * This code is derived from software contributed to Berkeley by
  10.  * Jan-Simon Pendry at Imperial College, London.
  11.  *
  12.  * Redistribution and use in source and binary forms are permitted
  13.  * provided that the above copyright notice and this paragraph are
  14.  * duplicated in all such forms and that any documentation,
  15.  * advertising materials, and other materials related to such
  16.  * distribution and use acknowledge that the software was developed
  17.  * by Imperial College of Science, Technology and Medicine, London, UK.
  18.  * The names of the College and University may not be used to endorse
  19.  * or promote products derived from this software without specific
  20.  * prior written permission.
  21.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  22.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  23.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  *
  25.  *    %W% (Berkeley) %G%
  26.  */
  27.  
  28. /*
  29.  * Utils
  30.  */
  31.  
  32. #include "am.h"
  33. #ifdef HAS_SYSLOG
  34. #include <syslog.h>
  35. #endif
  36. #include <ctype.h>
  37. #include <sys/stat.h>
  38.  
  39. #include <netdb.h>
  40.  
  41.  
  42. INLINE
  43. char *strnsave(str, len)
  44. const char *str;
  45. int len;
  46. {
  47.     char *sp = (char *) xmalloc(len+1);
  48.  
  49.     bcopy(str, sp, len);
  50.     sp[len] = 0;
  51.  
  52.     return sp;
  53. }
  54.  
  55. char *strdup(s)
  56. const char *s;
  57. {
  58.     return strnsave(s, strlen(s));
  59. }
  60.  
  61. /*
  62.  * Concatenate three strings and store in buffer pointed to
  63.  * by p, making p large enough to hold the strings
  64.  */
  65. char *str3cat(p, s1, s2, s3)
  66. char *p;
  67. char *s1;
  68. char *s2;
  69. char *s3;
  70. {
  71.     int l1 = strlen(s1);
  72.     int l2 = strlen(s2);
  73.     int l3 = strlen(s3);
  74.     p = (char *) xrealloc(p, l1 + l2 + l3 + 1);
  75.     bcopy(s1, p, l1);
  76.     bcopy(s2, p + l1, l2);
  77.     bcopy(s3, p + l1 + l2, l3 + 1);
  78.     return p;
  79. }
  80.  
  81. char *strealloc(p, s)
  82. char *p;
  83. char *s;
  84. {
  85.     int len = strlen(s) + 1;
  86.  
  87.     p = (char *) xrealloc((voidp) p, len);
  88.  
  89.     strcpy(p, s);
  90. #ifdef DEBUG_MEM
  91.     malloc_verify();
  92. #endif
  93.     return p;
  94. }
  95.  
  96. voidp xrealloc(ptr, len)
  97. voidp ptr;
  98. int len;
  99. {
  100. #if defined(DEBUG) && defined(DEBUG_MEM)
  101.     Debug(D_MEM) plog(XLOG_DEBUG, "Reallocated size %d; block %#x", len, ptr);
  102. #endif
  103.  
  104.     if (ptr)
  105.         ptr = (voidp) realloc(ptr, (unsigned) len);
  106.     else
  107.         ptr = (voidp) xmalloc((unsigned) len);
  108.  
  109.     if (!ptr) {
  110.         plog(XLOG_FATAL, "Out of memory in realloc");
  111.         going_down(1);
  112.         abort();
  113.     }
  114.     return ptr;
  115. }
  116.  
  117. char **strsplit(s, qc)
  118. char *s;
  119. int qc;
  120. {
  121.     char **ivec;
  122.     int ic = 0;
  123.     int done = 0;
  124.  
  125.     ivec = (char **) xmalloc((ic+1)*sizeof(char *));
  126.  
  127.     while (!done) {
  128.         char *v;
  129.         /*
  130.          * skip white space
  131.          */
  132.         while (*s && isascii(*s) && isspace(*s))
  133.             s++;
  134.  
  135.         /*
  136.          * End of string?
  137.          */
  138.         if (!*s)
  139.             break;
  140.  
  141.         /*
  142.          * remember start of string
  143.          */
  144.         v = s;
  145.  
  146.         /*
  147.          * skip to white space
  148.          */
  149.         while (*s && (!isascii(*s) || !isspace(*s))) {
  150.             if (*s++ == qc) {
  151.                 /*
  152.                  * Skip past string.
  153.                  */
  154.                 s++;
  155.                 while (*s && *s != qc)
  156.                      s++;
  157.                 if (*s == qc)
  158.                     s++;
  159.             }
  160.         }
  161.  
  162.         if (!*s)
  163.             done = 1;
  164.         *s++ = '\0';
  165.  
  166.         /*
  167.          * save string in new ivec slot
  168.          */
  169.         ivec[ic++] = v;
  170.         ivec = (char **) xrealloc(ivec, (ic+1)*sizeof(char *));
  171. #ifdef DEBUG
  172.         Debug(D_STR)
  173.             plog(XLOG_DEBUG, "strsplit saved \"%s\"", v);
  174. #endif
  175.     }
  176.  
  177. #ifdef DEBUG
  178.     Debug(D_STR)
  179.         plog(XLOG_DEBUG, "strsplit saved a total of %d strings", ic);
  180. #endif
  181.  
  182.     ivec[ic] = 0;
  183.  
  184.     return ivec;
  185. }
  186.  
  187. /*
  188.  * Strip off the trailing part of a domain
  189.  * to produce a short-form domain relative
  190.  * to the local host domain.
  191.  * Note that this has no effect if the domain
  192.  * names do not have the same number of
  193.  * components.  If that restriction proves
  194.  * to be a problem then the loop needs recoding
  195.  * to skip from right to left and do partial
  196.  * matches along the way -- ie more expensive.
  197.  */
  198. static void domain_strip P((char *otherdom, char *localdom));
  199. static void domain_strip(otherdom, localdom)
  200. char *otherdom, *localdom;
  201. {
  202.         char *p1 = otherdom-1;
  203.     char *p2 = localdom-1;
  204.  
  205.         do {
  206.                 if (p1 = strchr(p1+1, '.'))
  207.                 if (p2 = strchr(p2+1, '.'))
  208.                 if (strcmp(p1+1, p2+1) == 0) {
  209.                         *p1 = '\0';
  210.                         break;
  211.                 }
  212.         } while (p1 && p2);
  213. }
  214.  
  215. /*
  216.  * Normalize a host name
  217.  */
  218. void host_normalize P((char **chp));
  219. void host_normalize(chp)
  220. char **chp;
  221. {
  222.     /*
  223.      * Normalize hosts is used to resolve host name aliases
  224.      * and replace them with the standard-form name.
  225.      * Invoked with "-n" command line option.
  226.      */
  227.     if (normalize_hosts) {
  228.         struct hostent *hp;
  229.         clock_valid = 0;
  230.         hp = gethostbyname(*chp);
  231.         if (hp && hp->h_addrtype == AF_INET) {
  232. #ifdef DEBUG
  233.             dlog("Hostname %s normalized to %s", *chp, hp->h_name);
  234. #endif
  235.             *chp = strealloc(*chp, hp->h_name);
  236.         }
  237.     }
  238.     domain_strip(*chp, hostd);
  239. }
  240.  
  241. /*
  242.  * Keys are not allowed to contain " ' ! or ; to avoid
  243.  * problems with macro expansions.
  244.  */
  245. static char invalid_keys[] = "\"'!;@ \t\n";
  246. int valid_key P((char *key));
  247. int valid_key(key)
  248. char *key;
  249. {
  250.     while (*key)
  251.         if (strchr(invalid_keys, *key++))
  252.             return FALSE;
  253.     return TRUE;
  254. }
  255.  
  256. void going_down P((int rc));
  257. void going_down(rc)
  258. int rc;
  259. {
  260.     if (foreground) {
  261.         if (amd_state != Start) {
  262.             if (amd_state != Done)
  263.                 return;
  264.             unregister_amq();
  265.         }
  266.     }
  267.     if (foreground) {
  268.         plog(XLOG_INFO, "Finishing with status %d", rc);
  269.     } else {
  270. #ifdef DEBUG
  271.         dlog("background process exiting with status %d", rc);
  272. #endif
  273.     }
  274.  
  275.     exit(rc);
  276. }
  277.  
  278. #ifdef DEBUG_MEM
  279. static int mem_bytes;
  280. static int orig_mem_bytes;
  281. static void checkup_mem(P_void)
  282. {
  283. extern struct mallinfo __mallinfo;
  284.     if (mem_bytes != __mallinfo.uordbytes) {
  285.         if (orig_mem_bytes == 0)
  286.             mem_bytes = orig_mem_bytes = __mallinfo.uordbytes;
  287.         else {
  288.             fprintf(logfp, "%s[%d]: ", progname, mypid);
  289.             if (mem_bytes < __mallinfo.uordbytes) {
  290.                 fprintf(logfp, "ALLOC: %d bytes",
  291.                     __mallinfo.uordbytes - mem_bytes);
  292.             } else {
  293.                 fprintf(logfp, "FREE: %d bytes",
  294.                     mem_bytes - __mallinfo.uordbytes);
  295.             }
  296.             mem_bytes = __mallinfo.uordbytes;
  297.             fprintf(logfp, ", making %d missing\n",
  298.                 mem_bytes - orig_mem_bytes);
  299.         }
  300.     }
  301.     malloc_verify();
  302. }
  303. #endif
  304.  
  305. /*
  306.  * Take a log format string and expand occurences of %m
  307.  * with the current error code take from errno.
  308.  */
  309. INLINE
  310. static void expand_error(f, e)
  311. char *f;
  312. char *e;
  313. {
  314.     extern int sys_nerr;
  315.     extern char *sys_errlist[];
  316.     char *p;
  317.     int error = errno;
  318.  
  319.     for (p = f; *e = *p; e++, p++) {
  320.         if (p[0] == '%' && p[1] == 'm') {
  321.             char *errstr;
  322.             if (error < 0 || error >= sys_nerr)
  323.                 errstr = 0;
  324.             else
  325.                 errstr = sys_errlist[error];
  326.             if (errstr)
  327.                 strcpy(e, errstr);
  328.             else
  329.                 sprintf(e, "Error %d", error);
  330.             e += strlen(e) - 1;
  331.             p++;
  332.         }
  333.     }
  334. }
  335.  
  336. /*
  337.  * Output the time of day and hostname to the logfile
  338.  */
  339. static void show_time_host_and_name(lvl)
  340. int lvl;
  341. {
  342. static time_t last_t = 0;
  343. static char *last_ctime = 0;
  344.     time_t t = clocktime();
  345.     char *sev;
  346.     extern char *ctime();
  347.  
  348. #if defined(DEBUG) && defined(PARANOID)
  349. extern char **gargv;
  350. #endif
  351.  
  352.     if (t != last_t) {
  353.         last_ctime = ctime(&t);
  354.         last_t = t;
  355.     }
  356.  
  357.     switch (lvl) {
  358.     case XLOG_FATAL:    sev = "fatal:"; break;
  359.     case XLOG_ERROR:     sev = "error:"; break;
  360.     case XLOG_USER:        sev = "user: "; break;
  361.     case XLOG_WARNING:    sev = "warn: "; break;
  362.     case XLOG_INFO:        sev = "info: "; break;
  363.     case XLOG_DEBUG:    sev = "debug:"; break;
  364.     case XLOG_MAP:        sev = "map:  "; break;
  365.     case XLOG_STATS:    sev = "stats:"; break;
  366.     default:        sev = "hmm:  "; break;
  367.     }
  368.     fprintf(logfp, "%15.15s %s %s[%d]/%s ",
  369.         last_ctime+4, hostname,
  370. #if defined(DEBUG) && defined(PARANOID)
  371.         gargv[0],
  372. #else
  373.         progname,
  374. #endif
  375.         mypid,
  376.         sev);
  377. }
  378.  
  379. #ifdef DEBUG
  380. /*VARARGS1*/
  381. void dplog(fmt, j,s,_,p,e,n,d,r,y)
  382. char *fmt;
  383. char *j, *s, *_, *p, *e, *n, *d, *r, *y;
  384. {
  385.     plog(XLOG_DEBUG, fmt, j,s,_,p,e,n,d,r,y);
  386. }
  387.  
  388. #endif
  389. /*VARARGS1*/
  390. void plog(lvl, fmt, j,s,_,p,e,n,d,r,y)
  391. int lvl;
  392. char *fmt;
  393. char *j, *s, *_, *p, *e, *n, *d, *r, *y;
  394. {
  395.     char msg[1024];
  396.     char efmt[1024];
  397.     char *ptr = msg;
  398.  
  399.     if (!(xlog_level & lvl))
  400.         return;
  401.  
  402. #ifdef DEBUG_MEM
  403.     checkup_mem();
  404. #endif
  405.  
  406.     expand_error(fmt, efmt);
  407.     sprintf(ptr, efmt, j,s,_,p,e,n,d,r,y);
  408.     ptr += strlen(ptr);
  409.     if (ptr[-1] == '\n')
  410.         *--ptr  = '\0';
  411. #ifdef HAS_SYSLOG
  412.     if (syslogging) {
  413.         switch(lvl) {    /* from mike <mcooper@usc.edu> */
  414.         case XLOG_FATAL:    lvl = LOG_CRIT; break;
  415.         case XLOG_ERROR:     lvl = LOG_ERR; break;
  416.         case XLOG_USER:        lvl = LOG_WARNING; break;
  417.         case XLOG_WARNING:    lvl = LOG_WARNING; break;
  418.         case XLOG_INFO:        lvl = LOG_INFO; break;
  419.         case XLOG_DEBUG:    lvl = LOG_DEBUG; break;
  420.         case XLOG_MAP:        lvl = LOG_DEBUG; break;
  421.         case XLOG_STATS:    lvl = LOG_INFO; break;
  422.         default:        lvl = LOG_ERR; break;
  423.         }
  424.         syslog(lvl, "%s", msg);
  425.         return;
  426.     }
  427. #endif
  428.  
  429.     *ptr++ = '\n';
  430.     *ptr = '\0';
  431.  
  432.     /*
  433.      * Mimic syslog header
  434.      */
  435.     show_time_host_and_name(lvl);
  436.     fwrite(msg, ptr - msg, 1, logfp);
  437.     fflush(logfp);
  438. }
  439.  
  440. int bind_resv_port P((int so, u_short *pp));
  441. int bind_resv_port(so, pp)
  442. int so;
  443. u_short *pp;
  444. {
  445.     struct sockaddr_in sin;
  446.     int rc;
  447.     unsigned short port;
  448.  
  449.     bzero((voidp) &sin, sizeof(sin));
  450.     sin.sin_family = AF_INET;
  451.  
  452.     port = IPPORT_RESERVED;
  453.  
  454.     do {
  455.         --port;
  456.         sin.sin_port = htons(port);
  457.         rc = bind(so, (struct sockaddr *) &sin, sizeof(sin));
  458.     } while (rc < 0 && port > IPPORT_RESERVED/2);
  459.  
  460.     if (pp && rc == 0)
  461.         *pp = port;
  462.     return rc;
  463. }
  464.  
  465. void forcibly_timeout_mp P((am_node *mp));
  466. void forcibly_timeout_mp(mp)
  467. am_node *mp;
  468. {
  469.     mntfs *mf = mp->am_mnt;
  470.     /*
  471.      * Arrange to timeout this node
  472.      */
  473.     if (mf && ((mp->am_flags & AMF_ROOT) ||
  474.         (mf->mf_flags & (MFF_MOUNTING|MFF_UNMOUNTING)))) {
  475.         if (!(mf->mf_flags & MFF_UNMOUNTING))
  476.             plog(XLOG_WARNING, "ignoring timeout request for active node %s", mp->am_path);
  477.     } else {
  478.         plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path);
  479.         mp->am_flags &= ~AMF_NOTIMEOUT;
  480.         mp->am_ttl = clocktime();
  481.         reschedule_timeout_mp();
  482.     }
  483. }
  484.  
  485. void am_mounted P((am_node *mp));
  486. void am_mounted(mp)
  487. am_node *mp;
  488. {
  489.     mntfs *mf = mp->am_mnt;
  490.     int quoted;
  491.     mf->mf_flags |= MFF_MOUNTED;
  492.     mf->mf_error = 0;
  493.  
  494.     /*
  495.      * Patch up path for direct mounts
  496.      */
  497.     if (mp->am_parent && mp->am_parent->am_mnt->mf_ops == &dfs_ops)
  498.         mp->am_path = str3cat(mp->am_path, mp->am_parent->am_path, "/", ".");
  499.  
  500.     /*
  501.      * Check whether this mount should be cached permanently
  502.      */
  503.     if (mf->mf_ops->fs_flags & FS_NOTIMEOUT) {
  504.         mp->am_flags |= AMF_NOTIMEOUT;
  505.     } else if (mf->mf_mount[1] == '\0' && mf->mf_mount[0] == '/') {
  506.         mp->am_flags |= AMF_NOTIMEOUT;
  507.     } else {
  508.         struct mntent mnt;
  509.         mnt.mnt_opts = mf->mf_fo->opt_opts;
  510.         if (hasmntopt(&mnt, "nounmount"))
  511.             mp->am_flags |= AMF_NOTIMEOUT;
  512.         if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0)
  513.             mp->am_timeo = am_timeo;
  514. /*        if ((mf->mf_server->fs_pinger = hasmntval(&mnt, "ping")) == 0)
  515.             mf->mf_server->fs_pinger = AM_PINGER;
  516. */
  517.     }
  518.  
  519.     /*
  520.      * Do mounted callback
  521.      */
  522.     if (mf->mf_ops->mounted)
  523.         (*mf->mf_ops->mounted)(mf);
  524.  
  525.     /*
  526.      * If this node is a symlink then
  527.      * compute the length of the returned string.
  528.      */
  529.     if (mf->mf_fattr.type == NFLNK)
  530.         mf->mf_fattr.size = strlen(mp->am_link ? mp->am_link : mp->am_mnt->mf_mount);
  531.  
  532.     /*
  533.      * Record mount time
  534.      */
  535.     mp->am_stats.s_mtime = clocktime();
  536.     new_ttl(mp);
  537.  
  538.     /*
  539.      * Log message
  540.      */
  541.     quoted = strchr(mf->mf_info, ' ') != 0;
  542.     plog(XLOG_INFO, "%s%s%s mounted fstype %s on %s",
  543.         quoted ? "\"" : "",
  544.         mf->mf_info,
  545.         quoted ? "\"" : "",
  546.         mf->mf_ops->fs_type, mf->mf_mount);
  547.  
  548.     /*
  549.      * Update stats
  550.      */
  551.     amd_stats.d_mok++;
  552. }
  553.  
  554. int mount_node P((am_node *mp));
  555. int mount_node(mp)
  556. am_node *mp;
  557. {
  558.     mntfs *mf = mp->am_mnt;
  559.     int error;
  560.  
  561.     mf->mf_flags |= MFF_MOUNTING;
  562.     error = (*mf->mf_ops->mount_fs)(mp);
  563.     mf = mp->am_mnt;
  564.     mf->mf_flags &= ~MFF_MOUNTING;
  565.     if (!error && !(mf->mf_ops->fs_flags & FS_MBACKGROUND)) {
  566.         /* ...but see ifs_mount */
  567.         am_mounted(mp);
  568.     }
  569.  
  570.     return error;
  571. }
  572.  
  573. void am_unmounted P((am_node *mp));
  574. void am_unmounted(mp)
  575. am_node *mp;
  576. {
  577.     mntfs *mf = mp->am_mnt;
  578.  
  579.     if (!foreground) /* firewall - should never happen */
  580.         return;
  581.  
  582. #ifdef DEBUG
  583.     /*dlog("in am_unmounted(), foreground = %d", foreground);*/
  584. #endif
  585.  
  586.     /*
  587.      * Do unmounted callback
  588.      */
  589.     if (mf->mf_ops->umounted)
  590.         (*mf->mf_ops->umounted)(mp);
  591.  
  592.     free_map(mp);
  593. }
  594.  
  595.  
  596. /*
  597.  * Fork the automounter
  598.  *
  599.  * TODO: Need a better strategy for handling errors
  600.  */
  601. static int dofork(P_void);
  602. INLINE
  603. static int dofork()
  604. {
  605.     int pid;
  606. top:
  607.     pid = fork();
  608.  
  609.     if (pid < 0) {
  610.         sleep(1);
  611.         goto top;
  612.     }
  613.  
  614.     if (pid == 0) {
  615.         mypid = getpid();
  616.         foreground = 0;
  617.     }
  618.  
  619.     return pid;
  620. }
  621.  
  622. int background(P_void);
  623. int background()
  624. {
  625.     int pid = dofork();
  626.     if (pid == 0) {
  627. #ifdef DEBUG
  628.         dlog("backgrounded");
  629. #endif
  630.         foreground = 0;
  631.     }
  632.  
  633.     return pid;
  634. }
  635.  
  636. int mkdirs P((char *path, int mode));
  637. int mkdirs(path, mode)
  638. char *path;
  639. int mode;
  640. {
  641.     /*
  642.      * take a copy in case path is in readonly store
  643.      */
  644.     char *p2 = strdup(path);
  645.     char *sp = p2;
  646.     struct stat stb;
  647.     int error_so_far = 0;
  648.  
  649.     /*
  650.      * Skip through the string make the directories.
  651.      * Mostly ignore errors - the result is tested at the end.
  652.      *
  653.      * This assumes we are root so that we can do mkdir in a
  654.      * mode 555 directory...
  655.      */
  656.     while (sp = strchr(sp+1, '/')) {
  657.         *sp = '\0';
  658.         if (mkdir(p2, mode) < 0) {
  659.             error_so_far = errno;
  660.         } else {
  661. #ifdef DEBUG
  662.             dlog("mkdir(%s)", p2);
  663. #endif
  664.         }
  665.         *sp = '/';
  666.     }
  667.  
  668.     if (mkdir(p2, mode) < 0) {
  669.         error_so_far = errno;
  670.     } else {
  671. #ifdef DEBUG
  672.         dlog("mkdir(%s)", p2);
  673. #endif
  674.     }
  675.  
  676.     /*
  677.      * Do a sync - if we do rmdirs() immediately
  678.      * and then the system crashes it leaves
  679.      * the filesystem in a state that fsck -p
  680.      * can't fix.  (Observed more than once on
  681.      * SunOS 4 ...)
  682.      *
  683.      * This is an attempted workaround - XXX.
  684.      */
  685.     sync();
  686.  
  687.     free(p2);
  688.  
  689.     return stat(path, &stb) == 0 &&
  690.         (stb.st_mode & S_IFMT) == S_IFDIR ? 0 : error_so_far;
  691. }
  692.  
  693. void rmdirs P((char *dir));
  694. void rmdirs(dir)
  695. char *dir;
  696. {
  697.     char *xdp = strdup(dir);
  698.     char *dp;
  699.  
  700.     do {
  701.         struct stat stb;
  702.         /*
  703.          * Try to find out whether this was
  704.          * created by amd.  Do this by checking
  705.          * for owner write permission.
  706.          */
  707.         if (stat(xdp, &stb) == 0 && (stb.st_mode & 0200) == 0) {
  708.             if (rmdir(xdp) < 0) {
  709.                 if (errno != ENOTEMPTY && errno != EBUSY && errno != EEXIST)
  710.                     plog(XLOG_ERROR, "rmdir(%s): %m", xdp);
  711.                 break;
  712.             } else {
  713. #ifdef DEBUG
  714.                 dlog("rmdir(%s)", xdp);
  715. #endif
  716.             }
  717.         } else {
  718.             break;
  719.         }
  720.         dp = strrchr(xdp, '/');
  721.         if (dp)
  722.             *dp = '\0';
  723.     } while (dp && dp > xdp);
  724.     free(xdp);
  725. }
  726.  
  727. /*
  728.  * Because the internal clock is only used for
  729.  * timing out mounts, it does not have to be
  730.  * particularly accurate, so long as it does not run
  731.  * ahead of the real time.  So, to reduce the system
  732.  * call overhead, repeated calls to gettimeofday()
  733.  * are replaced by calls to the macro clocktime().
  734.  * If the global time (clock_valid) is zero then
  735.  * update_clocktime() is called to obtain the real time.
  736.  * Before any system calls that are likely to block for a
  737.  * significant time, the clock_valid value is set
  738.  * so that the clock is recomputed next time it is
  739.  * needed.
  740.  */
  741.  
  742. time_t clock_valid = 0;
  743. #ifndef clocktime
  744. time_t clocktime(P_void)
  745. {
  746.     return time(&clock_valid);
  747. }
  748. #endif
  749.  
  750. voidp xmalloc(len)
  751. int len;
  752. {
  753.     voidp p;
  754.     int retries = 600;
  755.  
  756.     do {
  757.         p = (voidp) malloc((unsigned) len);
  758.         if (p) {
  759. #if defined(DEBUG) && defined(DEBUG_MEM)
  760.             Debug(D_MEM) plog(XLOG_DEBUG, "Allocated size %d; block %#x", len, p);
  761. #endif
  762.             return p;
  763.         }
  764.         if (retries > 0) {
  765.             plog(XLOG_ERROR, "Retrying memory allocation");
  766.             sleep(1);
  767.         }
  768.     } while (--retries);
  769.  
  770.     plog(XLOG_FATAL, "Out of memory");
  771.     going_down(1);
  772.  
  773.     abort();
  774.  
  775.     return 0;
  776. }
  777.  
  778. #if defined(DEBUG) && defined(DEBUG_MEM)
  779. xfree(f, l, p)
  780. char *f;
  781. int l;
  782. voidp p;
  783. {
  784.     Debug(D_MEM) plog(XLOG_DEBUG, "Free in %s:%d: block %#x", f, l, p);
  785. #undef free
  786.     free(p);
  787. }
  788. #endif
  789.