- Make sure that the global cfg_file variable always contains
authorJan Janak <jan@iptel.org>
Fri, 8 Feb 2008 05:37:44 +0000 (05:37 +0000)
committerJan Janak <jan@iptel.org>
Fri, 8 Feb 2008 05:37:44 +0000 (05:37 +0000)
  full absolute pathname.
- Added get_abs_pathname function that can be used to convert
  relative pathnames to absolutes with using the location of
  cfg_file (or another file) as reference.

main.c
ut.c
ut.h

diff --git a/main.c b/main.c
index 85009c8..a5f8db9 100644 (file)
--- a/main.c
+++ b/main.c
 #ifdef HAVE_SYS_SOCKIO_H
 #include <sys/sockio.h>
 #endif
+#include <libgen.h>
 
 #include "config.h"
 #include "dprint.h"
@@ -893,6 +894,53 @@ error_port:
 }
 
 
+/** Update \c cfg_file variable to contain full pathname. The function updates
+ * the value of \c cfg_file global variable to contain full absolute pathname
+ * to the main configuration file of SER. The function uses CFG_FILE macro to
+ * determine the default path to the configuration file if the user did not
+ * specify one using the command line option. If \c cfg_file contains an
+ * absolute pathname then it is used unmodified, if it contains a relative
+ * pathanme than the value returned by \c getcwd function will be added at the
+ * beginning. This function must be run before SER changes its current working
+ * directory to / (in daemon mode).
+ * @return Zero on success, negative number
+ * on error.
+ */
+int fix_cfg_file(void)
+{
+       char* res = NULL;
+       size_t max_len, cwd_len, cfg_len;
+       
+       if (cfg_file == NULL) cfg_file = CFG_FILE;
+       if (cfg_file[0] == '/') return 0;
+       
+       /* cfg_file contains a relative pathname, get the current
+        * working directory and add it at the beginning
+        */
+       cfg_len = strlen(cfg_file);
+       
+       max_len = pathmax();
+       if ((res = malloc(max_len)) == NULL) goto error;
+       
+       if (getcwd(res, max_len) == NULL) goto error;
+       cwd_len = strlen(res);
+       
+       /* Make sure that the buffer is big enough */
+       if (cwd_len + 1 + cfg_len >= max_len) goto error;
+       
+       res[cwd_len] = '/';
+       memcpy(res + cwd_len + 1, cfg_file, cfg_len);
+       
+       res[cwd_len + 1 + cfg_len] = '\0'; /* Add terminating zero */
+       cfg_file = res;
+       return 0;
+       
+ error:
+       fprintf(stderr, "ERROR: Unable to fix cfg_file to contain full pathname\n");
+       if (res) free(res);
+       return -1;
+}
+
 
 /* main loop */
 int main_loop()
@@ -1350,8 +1398,9 @@ int main(int argc, char** argv)
 
        if (init_routes()<0) goto error;
        if (init_nonsip_hooks()<0) goto error;
-       /* fill missing arguments with the default values*/
-       if (cfg_file==0) cfg_file=CFG_FILE;
+
+       /* Fix the value of cfg_file variable.*/
+       if (fix_cfg_file() < 0) goto error;
 
        /* load config file or die */
        cfg_stream=fopen (cfg_file, "r");
diff --git a/ut.c b/ut.c
index 1c6f2a8..b048f61 100644 (file)
--- a/ut.c
+++ b/ut.c
@@ -28,7 +28,7 @@
  *
  */
 
-
+#define _GNU_SOURCE 1 /* strndup in get_abs_pathname */
 #include <string.h>
 #include <sys/types.h>
 #include <pwd.h>
@@ -40,6 +40,7 @@
 
 #include "ut.h"
 #include "mem/mem.h"
+#include "globals.h"
 
 
 /* converts a username into uid:gid,
@@ -204,4 +205,57 @@ unsigned int get_sys_version(int* major, int* minor, int* minor2)
 }
 
 
-
+char* get_abs_pathname(str* base, str* file)
+{
+       str ser_cfg;
+       char* buf, *dir, *res;
+       int len;
+       
+       if (base == NULL) {
+               ser_cfg.s = cfg_file;
+               ser_cfg.len = strlen(cfg_file);
+               base = &ser_cfg;
+       }
+       
+       if (!base->s || base->len <= 0 || base->s[0] != '/') {
+               BUG("get_abs_pathname: Base file must be absolute pathname: "
+                       "'%.*s'\n", STR_FMT(base));
+               return NULL;
+       }
+       
+       if (!file || !file->s || file->len <= 0) {
+               BUG("get_abs_pathname: Invalid 'file' parameter\n");
+               return NULL;
+       }
+       
+       if (file->s[0] == '/') {
+               /* This is an absolute pathname, make a zero terminated
+                * copy and use it as it is */
+               if ((res = strndup(file->s, file->len)) == NULL) {
+                       ERR("get_abs_pathname: No memory left (strndup failed)\n");
+               }
+       } else {
+               /* This is not an absolute pathname, make it relative
+                * to the location of the base file
+                */
+               /* Make a copy, function dirname may modify the string */
+               if ((buf = strndup(base->s, base->len)) == NULL) {
+                       ERR("get_abs_pathname: No memory left (strdup failed)\n");
+                       return NULL;
+               }
+               dir = dirname(buf);
+               
+               len = strlen(dir);
+               if ((res = malloc(len + 1 + file->len + 1)) == NULL) {
+                       ERR("get_abs_pathname: No memory left (malloc failed)\n");
+                       free(buf);
+                       return NULL;
+               }
+               memcpy(res, dir, len);
+               res[len] = '/';
+               memcpy(res + len + 1, file->s, file->len);
+               res[len + 1 + file->len] = '\0';
+               free(buf);
+       }
+       return res;
+}
diff --git a/ut.h b/ut.h
index ae0df1a..674674a 100644 (file)
--- a/ut.h
+++ b/ut.h
@@ -580,4 +580,20 @@ char* as_asciiz(str* s);
  * if the parameters are not null they are set to the coresp. part */
 unsigned int get_sys_version(int* major, int* minor, int* minor2);
 
+/** Converts relative pathnames to absolute pathnames. This function returns
+ * the full pathname of a file in parameter. If the file pathname does not
+ * start with / then it will be converted into an absolute pathname. The
+ * function gets the absolute directory pathname from \c base and appends \c
+ * file to it. The first parameter can be NULL, in this case the function will
+ * use the location of the main SER configuration file as reference.
+ * @param base filename to be used as reference when \c file is relative. It
+ *             must be absolute. The location of the SER configuration file
+ *             will be used as reference if you set the value of this
+ *             parameter to NULL.
+ * @param file A pathname to be converted to absolute.
+ * @return A string containing absolute pathname, the string must be freed
+ * with free. NULL on error.
+ */
+char* get_abs_pathname(str* base, str* file);
+
 #endif