Add systemd notify support
[src/drm-lease-manager.git] / drm-lease-manager / main.c
1 /* Copyright 2020-2021 IGEL Co., Ltd.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include "config.h"
17 #include "lease-config.h"
18 #include "lease-manager.h"
19 #include "lease-server.h"
20 #include "log.h"
21
22 #include <assert.h>
23 #include <getopt.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26
27 #ifdef HAVE_SYSTEMD_DAEMON
28 #include <systemd/sd-daemon.h>
29 #endif
30
31 static void usage(const char *progname)
32 {
33         printf("Usage: %s [OPTIONS] [<DRM device>]\n\n"
34                "Options:\n"
35                "-h, --help \tPrint this help\n"
36                "-c, --config \t path to configuration file (default "
37                "/etc/drm-lease-manager.toml)\n"
38                "-v, --verbose \tEnable verbose debug messages\n"
39                "-t, --lease-transfer \tAllow lease transfter to new clients\n"
40                "-k, --keep-on-crash \tDon't close lease on client crash\n",
41                progname);
42 }
43
44 const char *opts = "vtkhc:";
45 const struct option options[] = {
46     {"help", no_argument, NULL, 'h'},
47     {"verbose", no_argument, NULL, 'v'},
48     {"lease-transfer", no_argument, NULL, 't'},
49     {"keep-on-crash", no_argument, NULL, 'k'},
50     {"config", required_argument, NULL, 'c'},
51     {NULL, 0, NULL, 0},
52 };
53
54 int main(int argc, char **argv)
55 {
56         char *device = NULL;
57         char *config_file = "/etc/drm-lease-manager.toml";
58
59         bool debug_log = false;
60         bool can_transfer_leases = false;
61         bool keep_on_crash = false;
62
63         int c;
64         while ((c = getopt_long(argc, argv, opts, options, NULL)) != -1) {
65                 int ret = EXIT_FAILURE;
66                 switch (c) {
67                 case 'v':
68                         debug_log = true;
69                         break;
70                 case 't':
71                         can_transfer_leases = true;
72                         break;
73                 case 'k':
74                         keep_on_crash = true;
75                         break;
76                 case 'c':
77                         config_file = optarg;
78                         break;
79                 case 'h':
80                         ret = EXIT_SUCCESS;
81                         /* fall through */
82                 default:
83                         usage(argv[0]);
84                         return ret;
85                 }
86         }
87
88         if (optind < argc)
89                 device = argv[optind];
90
91         dlm_log_enable_debug(debug_log);
92
93         struct lease_config *lease_configs = NULL;
94         int num_configs = parse_config(config_file, &lease_configs);
95
96         struct lm *lm =
97             lm_create_with_config(device, num_configs, lease_configs);
98
99         if (!lm) {
100                 ERROR_LOG("DRM Lease initialization failed\n");
101                 return EXIT_FAILURE;
102         }
103
104         struct lease_handle **lease_handles = NULL;
105         int count_ids = lm_get_lease_handles(lm, &lease_handles);
106         assert(count_ids > 0);
107
108         struct ls *ls = ls_create(lease_handles, count_ids);
109         if (!ls) {
110                 lm_destroy(lm);
111                 ERROR_LOG("Client socket initialization failed\n");
112                 return EXIT_FAILURE;
113         }
114
115 #ifdef HAVE_SYSTEMD_DAEMON
116         sd_notify(1, "READY=1");
117 #endif
118
119         struct ls_req req;
120         while (ls_get_request(ls, &req)) {
121                 switch (req.type) {
122                 case LS_REQ_GET_LEASE: {
123                         int fd = lm_lease_grant(lm, req.lease_handle);
124
125                         if (fd < 0 && can_transfer_leases)
126                                 fd = lm_lease_transfer(lm, req.lease_handle);
127
128                         if (fd < 0) {
129                                 ERROR_LOG(
130                                     "Can't fulfill lease request: lease=%s\n",
131                                     req.lease_handle->name);
132                                 ls_disconnect_client(ls, req.client);
133                                 break;
134                         }
135
136                         struct ls_client *active_client =
137                             req.lease_handle->user_data;
138                         if (active_client)
139                                 ls_disconnect_client(ls, active_client);
140
141                         req.lease_handle->user_data = req.client;
142
143                         if (!ls_send_fd(ls, req.client, fd)) {
144                                 ERROR_LOG(
145                                     "Client communication error: lease=%s\n",
146                                     req.lease_handle->name);
147                                 ls_disconnect_client(ls, req.client);
148                                 lm_lease_revoke(lm, req.lease_handle);
149                         }
150                         break;
151                 }
152                 case LS_REQ_RELEASE_LEASE:
153                 case LS_REQ_CLIENT_DISCONNECT:
154                         ls_disconnect_client(ls, req.client);
155                         req.lease_handle->user_data = NULL;
156                         lm_lease_revoke(lm, req.lease_handle);
157
158                         if (!keep_on_crash || req.type == LS_REQ_RELEASE_LEASE)
159                                 lm_lease_close(req.lease_handle);
160
161                         break;
162                 default:
163                         ERROR_LOG("Internal error: Invalid lease request\n");
164                         goto done;
165                 }
166         }
167 done:
168         ls_destroy(ls);
169         lm_destroy(lm);
170         release_config(num_configs, lease_configs);
171         return EXIT_FAILURE;
172 }