svc - Initial commit, preliminary service manager
[dragonfly.git] / sbin / svc / subs.c
1 /*
2  * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 /*
35  * Support routines
36  */
37
38 #include "svc.h"
39
40 void
41 sfree(char **strp)
42 {
43         if (*strp)
44                 free(*strp);
45 }
46
47 void
48 sreplace(char **strp, const char *orig)
49 {
50         if (*strp) {
51                 free(*strp);
52                 *strp = NULL;
53         }
54         if (orig)
55                 *strp = strdup(orig);
56 }
57
58 void
59 sdup(char **strp)
60 {
61         if (*strp)
62                 *strp = strdup(*strp);
63 }
64
65 void
66 afree(char ***aryp)
67 {
68         char **ary = *aryp;
69         int i;
70
71         if (ary) {
72                 for (i = 0; ary[i]; ++i)
73                         free(ary[i]);
74                 free(ary);
75         }
76         *aryp = NULL;
77 }
78
79 void
80 adup(char ***aryp)
81 {
82         char **ary = *aryp;
83         char **nary;
84         int i;
85
86         if (ary) {
87                 for (i = 0; ary[i]; ++i)
88                         ;
89                 nary = calloc(sizeof(char *), i + 1);
90                 bcopy(ary, nary, sizeof(char *) * (i + 1));
91                 for (i = 0; nary[i]; ++i)
92                         nary[i] = strdup(nary[i]);
93                 *aryp = nary;
94         }
95 }
96
97 /*
98  * Sets up the pidfile and unix domain socket.  We do not yet know the
99  * pid to store in the pidfile.
100  */
101 int
102 setup_pid_and_socket(command_t *cmd, int *lfdp, int *pfdp)
103 {
104         struct sockaddr_un sou;
105         size_t len;
106         char *pidfile;
107
108         /*
109          * Create and test the pidfile.
110          */
111         asprintf(&pidfile, "%s/service.%s.pid", cmd->piddir, cmd->label);
112         *lfdp = -1;
113         *pfdp = open(pidfile, O_RDWR|O_CREAT|O_EXLOCK|O_NONBLOCK, 0644);
114         if (*pfdp < 0) {
115                 if (errno == EWOULDBLOCK) {
116                         fprintf(cmd->fp, "Cannot init, %s is already active\n",
117                                 cmd->label);
118                 } else {
119                         fprintf(cmd->fp,
120                                 "Cannot init, unable to create \"%s\": %s\n",
121                                 cmd->label,
122                                 strerror(errno));
123                 }
124                 free(pidfile);
125                 return 1;
126         }
127         ftruncate(*pfdp, 0);
128
129         /*
130          * Create the unix-domain socket.
131          */
132         bzero(&sou, sizeof(sou));
133         if ((*lfdp = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) {
134                 sou.sun_family = AF_UNIX;
135                 snprintf(sou.sun_path, sizeof(sou.sun_path),
136                          "%s/service.%s.sk", cmd->piddir, cmd->label);
137                 len = strlen(sou.sun_path);
138                 len = offsetof(struct sockaddr_un, sun_path[len+1]);
139
140                 /* remove stale file before trying to bind */
141                 remove(sou.sun_path);
142
143                 if (bind(*lfdp, (void *)&sou, len) < 0) {
144                         fprintf(cmd->fp, "Unable to bind \"%s\"\n",
145                                 sou.sun_path);
146                         close(*lfdp);
147                         *lfdp = -1;
148                 } else if (listen(*lfdp, 32) < 0) {
149                         fprintf(cmd->fp, "Unable to listen on \"%s\"\n",
150                                 sou.sun_path);
151                         close(*lfdp);
152                         *lfdp = -1;
153                 }
154         } else {
155                 fprintf(cmd->fp, "Unable to create unix-domain socket\n");
156         }
157         if (*lfdp >= 0) {
158                 return 0;
159         } else {
160                 close(*pfdp);
161                 *pfdp = -1;
162
163                 return 1;
164         }
165 }