Check-in [4626ecb025]
Overview
Comment:Added start of TSMF service starter
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 4626ecb025883b8239edcd9b00307370c299f998
User & Date: rkeene on 2012-09-09 07:41:55
Other Links: manifest | tags
Context
2012-09-09
21:18
Started processing "umask" and "cwd" arguments Updated to have 30sec (currently hard-coded) timeout for starting processes check-in: 4b855bb7b2 user: rkeene tags: trunk
07:41
Added start of TSMF service starter check-in: 4626ecb025 user: rkeene tags: trunk
2012-08-22
03:36
Added stub for "vconfig" check-in: 1fce677508 user: rkeene tags: trunk
Changes

Modified system.c from [ea988bbb17] to [af68cfea10].

     4      4   #include <arpa/inet.h>
     5      5   #include <sys/socket.h>
     6      6   #include <sys/mount.h>
     7      7   #include <sys/types.h>
     8      8   #include <sys/ioctl.h>
     9      9   #include <sys/swap.h>
    10     10   #include <sys/stat.h>
           11  +#include <sys/wait.h>
    11     12   #include <stdlib.h>
    12     13   #include <signal.h>
    13     14   #include <unistd.h>
    14     15   #include <string.h>
    15     16   #include <fcntl.h>
    16     17   #include <errno.h>
           18  +#include <time.h>
    17     19   #include <tcl.h>
    18     20   
    19     21   #include <linux/sockios.h>
    20     22   #include <linux/route.h>
    21     23   #include <linux/if.h>
    22     24   #include <linux/if_arp.h>
    23     25   #include <linux/if_bridge.h>
................................................................................
    35     37   #endif
    36     38   #ifndef MNT_EXPIRE
    37     39   #define MNT_EXPIRE 4
    38     40   #endif
    39     41   #ifndef MS_MOVE
    40     42   #define MS_MOVE 8192
    41     43   #endif
           44  +
           45  +/* Simple macros */
           46  +#ifndef MAX
           47  +#define MAX(a, b) (((a) < (b)) ? (b) : (a))
           48  +#endif
           49  +#ifndef MIN
           50  +#define MIN(a, b) (((a) < (b)) ? (a) : (b))
           51  +#endif
    42     52   
    43     53   /* User environment, for execve */
    44     54   extern char **environ;
    45     55   
    46     56   /* Re-implement these if needed */
    47     57   #ifdef SYS_init_module
    48     58   static int init_module(void *val, unsigned long len, const char *args) {
................................................................................
  1862   1872   
  1863   1873   	if (sock_v6 != -1) {
  1864   1874   		close(sock_v6);
  1865   1875   	}
  1866   1876   
  1867   1877   	return(retval);
  1868   1878   }
         1879  +
         1880  +static int tclsystem_tsmf_start_svc(ClientData cd, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) {
         1881  +	Tcl_Obj *filename_obj, *env_obj, *logfile_obj, **env_entry_objv;
         1882  +	pid_t child, child_pgid = -1;
         1883  +	ssize_t read_ret;
         1884  +	time_t currtime;
         1885  +	char *argv[3], *envv[512];
         1886  +	char *logfile, *filename;
         1887  +	char logmsg[2048];
         1888  +	int pipe_ret, setsid_ret, execve_ret, tcl_ret;
         1889  +	int null_fd, log_fd, tmp_fd, max_fd;
         1890  +	int env_entry_objc;
         1891  +	int fds[2], fd;
         1892  +	int status;
         1893  +	int idx;
         1894  +
         1895  +	/* 1. Parse arguments */
         1896  +	/* 1.a. Ensure the correct number of arguments were passed */
         1897  +	if (objc != 9) {
         1898  +		Tcl_SetObjResult(interp, Tcl_NewStringObj("wrong # args: should be \"::system::syscall::tsmf_start_svc sri filename logfile env cwd umask user group\"", -1));
         1899  +
         1900  +		return(TCL_ERROR);
         1901  +	}
         1902  +
         1903  +	/* 1.b. Identify Tcl_Objs to use for each argument */
         1904  +	filename_obj = objv[2];
         1905  +	logfile_obj = objv[3];
         1906  +	env_obj = objv[4];
         1907  +
         1908  +	/* 1.c. Store string arguments */
         1909  +	filename = Tcl_GetString(filename_obj);
         1910  +	logfile = Tcl_GetString(logfile_obj);
         1911  +
         1912  +	/* 1.d. Process environment */
         1913  +	tcl_ret = Tcl_ListObjGetElements(interp, env_obj, &env_entry_objc, &env_entry_objv);
         1914  +	if (tcl_ret != TCL_OK) {
         1915  +		return(tcl_ret);
         1916  +	}
         1917  +
         1918  +	for (idx = 0; idx < MIN(env_entry_objc, sizeof(envv) / sizeof(envv[0]) - 1); idx++) {
         1919  +		envv[idx] = Tcl_GetString(env_entry_objv[idx]);
         1920  +	}
         1921  +	envv[idx] = NULL;
         1922  +
         1923  +	/* 2. Create a pipe for communication between the processes */
         1924  +	pipe_ret = pipe(fds);
         1925  +	if (pipe_ret != 0) {
         1926  +		Tcl_SetObjResult(interp, Tcl_NewStringObj("pipe failed", -1));
         1927  +
         1928  +		return(TCL_ERROR);
         1929  +	}
         1930  +
         1931  +	/* 3. Fork into a new process */
         1932  +	child = fork();
         1933  +	if (child == ((pid_t) -1)) {
         1934  +		Tcl_SetObjResult(interp, Tcl_NewStringObj("fork failed", -1));
         1935  +
         1936  +		return(TCL_ERROR);
         1937  +	}
         1938  +
         1939  +	if (child != 0) {
         1940  +		/* 4.parent. Get PGID from child */
         1941  +		/* 4.parent.a. Close write end of pipe -- we are read-only */
         1942  +		close(fds[1]);
         1943  +		fd = fds[0];
         1944  +
         1945  +		/* 4.parent.b. Read process group ID of child from pipe */
         1946  +		read_ret = read(fd, &child_pgid, sizeof(child_pgid));
         1947  +
         1948  +		/* 4.parent.c. Close read end of pipe */
         1949  +		close(fd);
         1950  +
         1951  +		/* 4.parent.d. Verify read was meaningful */
         1952  +		if (read_ret != sizeof(child_pgid)) {
         1953  +			Tcl_SetObjResult(interp, Tcl_NewStringObj("failed to communicate with started service", -1));
         1954  +
         1955  +			return(TCL_ERROR);
         1956  +		}
         1957  +
         1958  +		/* 4.parent.e. If the PGID given is actually an error, return error */
         1959  +		if (child_pgid == ((pid_t) -1)) {
         1960  +			Tcl_SetObjResult(interp, Tcl_NewStringObj("service failed to start", -1));
         1961  +
         1962  +			return(TCL_ERROR);
         1963  +		}
         1964  +
         1965  +		/* 4.parent.f. Return PGID to Tcl */
         1966  +		Tcl_SetObjResult(interp, Tcl_NewWideIntObj((Tcl_WideInt) child_pgid));
         1967  +
         1968  +		return(TCL_OK);
         1969  +	}
         1970  +
         1971  +	/* 4.child.a. Close read end of pipe -- we only write to it */
         1972  +	close(fds[0]);
         1973  +	fd = fds[1];
         1974  +
         1975  +	/* 5. Create a new session */
         1976  +	setsid_ret = setsid();
         1977  +	if (setsid_ret == ((pid_t) -1)) {
         1978  +		write(fd, &child_pgid, sizeof(child_pgid));
         1979  +
         1980  +		_exit(0);
         1981  +	}
         1982  +
         1983  +	/* 6. Setup environment */
         1984  +	/* 6.a. Set umask */
         1985  +	/* XXX: TODO */
         1986  +	umask(022);
         1987  +
         1988  +	/* 6.b. Set working directory */
         1989  +	/* XXX: TODO */
         1990  +	chdir("/");
         1991  +
         1992  +	/* 6.c. Open log file for stderr and stdout */
         1993  +	log_fd = open(logfile, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
         1994  +
         1995  +	/* 6.d. Open "/dev/null" for stdin */
         1996  +	null_fd = open("/dev/null", O_RDONLY);
         1997  +	if (null_fd < 0 || log_fd <0) {
         1998  +		write(fd, &child_pgid, sizeof(child_pgid));
         1999  +
         2000  +		_exit(0);
         2001  +	}
         2002  +
         2003  +	/* 6.e. Redirect stdin, stdout, and stderr to null, logs */
         2004  +	dup2(null_fd, STDIN_FILENO);
         2005  +	dup2(log_fd, STDOUT_FILENO);
         2006  +	dup2(log_fd, STDERR_FILENO);
         2007  +
         2008  +	close(null_fd);
         2009  +	close(log_fd);
         2010  +
         2011  +	/* 6.f. Close stray file descriptors */
         2012  +	max_fd = MAX(MAX(MAX(1024, STDIN_FILENO), STDOUT_FILENO), STDERR_FILENO);
         2013  +	for (tmp_fd = 0; tmp_fd < max_fd; tmp_fd++) {
         2014  +		if (tmp_fd == STDIN_FILENO || tmp_fd == STDOUT_FILENO || tmp_fd == STDERR_FILENO) {
         2015  +			continue;
         2016  +		}
         2017  +
         2018  +		if (tmp_fd == fd) {
         2019  +			continue;
         2020  +		}
         2021  +
         2022  +		close(tmp_fd);
         2023  +	}
         2024  +
         2025  +	/* 6.g. Switch to appropriate user/group */
         2026  +	/* 6.g.i. Group */
         2027  +	/* XXX: TODO */
         2028  +
         2029  +	/* 6.g.ii. User */
         2030  +	/* XXX: TODO */
         2031  +
         2032  +	/* 7. Create a new process to actually spawn the process */
         2033  +	child = fork();
         2034  +	if (child == ((pid_t) -1)) {
         2035  +		write(fd, &child_pgid, sizeof(child_pgid));
         2036  +
         2037  +		_exit(0);
         2038  +	}
         2039  +
         2040  +	if (child != 0) {
         2041  +		/* 7.parent.a. Wait for child process to terminate and collect status */
         2042  +		waitpid(child, &status, 0);
         2043  +
         2044  +		/* 7.parent.b. Set PGID (if successful, -1 otherwise) to pass back to TSMF */
         2045  +		if (status == 0) {
         2046  +			child_pgid = getpgid(getpid());
         2047  +		}
         2048  +		write(fd, &child_pgid, sizeof(child_pgid));
         2049  +
         2050  +		close(fd);
         2051  +
         2052  +		/* 7.parent.c. Write log of result */
         2053  +		/* Note: We avoid ANSI I/O here in case there is already something in the buffer */
         2054  +		currtime = time(NULL);
         2055  +		strftime(logmsg, sizeof(logmsg), "[ %b %e %H:%M:%S ", localtime(&currtime));
         2056  +		write(STDERR_FILENO, logmsg, strlen(logmsg));
         2057  +
         2058  +		snprintf(logmsg, sizeof(logmsg), "Method \"start\" exited with status %i ]\n", WEXITSTATUS(status));
         2059  +		write(STDERR_FILENO, logmsg, strlen(logmsg));
         2060  +
         2061  +		_exit(0);
         2062  +	}
         2063  +	
         2064  +	/* 7.child.a. Close channel to parent */
         2065  +	close(fd);
         2066  +
         2067  +	/* 8. Log attempt to run start method */
         2068  +	currtime = time(NULL);
         2069  +	strftime(logmsg, sizeof(logmsg), "[ %b %e %H:%M:%S ", localtime(&currtime));
         2070  +	write(STDERR_FILENO, logmsg, strlen(logmsg));
         2071  +
         2072  +	snprintf(logmsg, sizeof(logmsg), "Executing start method (\"%s\") ]\n", filename);
         2073  +	write(STDERR_FILENO, logmsg, strlen(logmsg));
         2074  +
         2075  +	/* 9. execve() new image */
         2076  +	argv[0] = filename;
         2077  +	argv[1] = "start";
         2078  +	argv[2] = NULL;
         2079  +	execve_ret = execve(filename, argv, envv);
         2080  +
         2081  +	/* 10. Abort if something has gone wrong */
         2082  +	_exit(execve_ret);
         2083  +}
  1869   2084   
  1870   2085   int System_Init(Tcl_Interp *interp) {
  1871   2086   #ifdef USE_TCL_STUBS
  1872   2087   	const char *tclInitStubs_ret;
  1873   2088   
  1874   2089   	/* Initialize Stubs */
  1875   2090   	tclInitStubs_ret = Tcl_InitStubs(interp, "8.4", 0);
................................................................................
  1905   2120   
  1906   2121   	/* Network related commands */
  1907   2122   	Tcl_CreateObjCommand(interp, "::system::syscall::ifconfig", tclsystem_ifconfig, NULL, NULL);
  1908   2123   	Tcl_CreateObjCommand(interp, "::system::syscall::route", tclsystem_route, NULL, NULL);
  1909   2124   	Tcl_CreateObjCommand(interp, "::system::syscall::brctl", tclsystem_brctl, NULL, NULL);
  1910   2125   	Tcl_CreateObjCommand(interp, "::system::syscall::vconfig", tclsystem_vconfig, NULL, NULL);
  1911   2126   
         2127  +	/* Service (TSMF) related commands */
         2128  +	Tcl_CreateObjCommand(interp, "::system::syscall::tsmf_start_svc", tclsystem_tsmf_start_svc, NULL, NULL);
         2129  +
  1912   2130   	/* Internal functions */
  1913   2131   	Tcl_CreateObjCommand(interp, "::system::internal::hash", tclsystem_internalproc_simplehash, NULL, NULL);
  1914   2132   
  1915   2133   	/* Define constants */
  1916   2134   	/** Create parent namespace **/
  1917   2135   	Tcl_CreateNamespace(interp, "::system::const", NULL, NULL);
  1918   2136