]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-bus.c
hwdb: Update database of Bluetooth company identifiers
[thirdparty/systemd.git] / src / resolve / resolved-bus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "bus-common-errors.h"
23 #include "bus-util.h"
24
25 #include "dns-domain.h"
26 #include "resolved-bus.h"
27 #include "resolved-def.h"
28
29 static int reply_query_state(DnsQuery *q) {
30 _cleanup_free_ char *ip = NULL;
31 const char *name;
32 int r;
33
34 if (q->request_hostname)
35 name = q->request_hostname;
36 else {
37 r = in_addr_to_string(q->request_family, &q->request_address, &ip);
38 if (r < 0)
39 return r;
40
41 name = ip;
42 }
43
44 switch (q->state) {
45
46 case DNS_TRANSACTION_NO_SERVERS:
47 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_NAME_SERVERS, "No appropriate name servers or networks for name found");
48
49 case DNS_TRANSACTION_TIMEOUT:
50 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "Query timed out");
51
52 case DNS_TRANSACTION_ATTEMPTS_MAX_REACHED:
53 return sd_bus_reply_method_errorf(q->request, SD_BUS_ERROR_TIMEOUT, "All attempts to contact name servers or networks failed");
54
55 case DNS_TRANSACTION_INVALID_REPLY:
56 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply");
57
58 case DNS_TRANSACTION_RESOURCES:
59 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_RESOURCES, "Not enough resources");
60
61 case DNS_TRANSACTION_ABORTED:
62 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_ABORTED, "Query aborted");
63
64 case DNS_TRANSACTION_FAILURE: {
65 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
66
67 if (q->answer_rcode == DNS_RCODE_NXDOMAIN)
68 sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", name);
69 else {
70 const char *rc, *n;
71 char p[3]; /* the rcode is 4 bits long */
72
73 rc = dns_rcode_to_string(q->answer_rcode);
74 if (!rc) {
75 sprintf(p, "%i", q->answer_rcode);
76 rc = p;
77 }
78
79 n = strjoina(_BUS_ERROR_DNS, rc);
80 sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", name, rc);
81 }
82
83 return sd_bus_reply_method_error(q->request, &error);
84 }
85
86 case DNS_TRANSACTION_NULL:
87 case DNS_TRANSACTION_PENDING:
88 case DNS_TRANSACTION_SUCCESS:
89 default:
90 assert_not_reached("Impossible state");
91 }
92 }
93
94 static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex) {
95 int r;
96
97 assert(reply);
98 assert(rr);
99
100 r = sd_bus_message_open_container(reply, 'r', "iiay");
101 if (r < 0)
102 return r;
103
104 r = sd_bus_message_append(reply, "i", ifindex);
105 if (r < 0)
106 return r;
107
108 if (rr->key->type == DNS_TYPE_A) {
109 r = sd_bus_message_append(reply, "i", AF_INET);
110 if (r < 0)
111 return r;
112
113 r = sd_bus_message_append_array(reply, 'y', &rr->a.in_addr, sizeof(struct in_addr));
114
115 } else if (rr->key->type == DNS_TYPE_AAAA) {
116 r = sd_bus_message_append(reply, "i", AF_INET6);
117 if (r < 0)
118 return r;
119
120 r = sd_bus_message_append_array(reply, 'y', &rr->aaaa.in6_addr, sizeof(struct in6_addr));
121 } else
122 return -EAFNOSUPPORT;
123
124 if (r < 0)
125 return r;
126
127 r = sd_bus_message_close_container(reply);
128 if (r < 0)
129 return r;
130
131 return 0;
132 }
133
134 static void bus_method_resolve_hostname_complete(DnsQuery *q) {
135 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL, *canonical = NULL;
136 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
137 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
138 unsigned added = 0, i;
139 int r;
140
141 assert(q);
142
143 if (q->state != DNS_TRANSACTION_SUCCESS) {
144 r = reply_query_state(q);
145 goto finish;
146 }
147
148 r = sd_bus_message_new_method_return(q->request, &reply);
149 if (r < 0)
150 goto finish;
151
152 r = sd_bus_message_open_container(reply, 'a', "(iiay)");
153 if (r < 0)
154 goto finish;
155
156 if (q->answer) {
157 answer = dns_answer_ref(q->answer);
158
159 for (i = 0; i < answer->n_rrs; i++) {
160 r = dns_question_matches_rr(q->question, answer->items[i].rr);
161 if (r < 0)
162 goto finish;
163 if (r == 0) {
164 /* Hmm, if this is not an address record,
165 maybe it's a cname? If so, remember this */
166 r = dns_question_matches_cname(q->question, answer->items[i].rr);
167 if (r < 0)
168 goto finish;
169 if (r > 0)
170 cname = dns_resource_record_ref(answer->items[i].rr);
171
172 continue;
173 }
174
175 r = append_address(reply, answer->items[i].rr, answer->items[i].ifindex);
176 if (r < 0)
177 goto finish;
178
179 if (!canonical)
180 canonical = dns_resource_record_ref(answer->items[i].rr);
181
182 added ++;
183 }
184 }
185
186 if (added == 0) {
187 if (!cname) {
188 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of requested type", q->request_hostname);
189 goto finish;
190 }
191
192 /* This has a cname? Then update the query with the
193 * new cname. */
194 r = dns_query_cname_redirect(q, cname->cname.name);
195 if (r < 0) {
196 if (r == -ELOOP)
197 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop on '%s'", q->request_hostname);
198 else
199 r = sd_bus_reply_method_errno(q->request, -r, NULL);
200
201 goto finish;
202 }
203
204 /* Before we restart the query, let's see if any of
205 * the RRs we already got already answers our query */
206 for (i = 0; i < answer->n_rrs; i++) {
207 r = dns_question_matches_rr(q->question, answer->items[i].rr);
208 if (r < 0)
209 goto finish;
210 if (r == 0)
211 continue;
212
213 r = append_address(reply, answer->items[i].rr, answer->items[i].ifindex);
214 if (r < 0)
215 goto finish;
216
217 if (!canonical)
218 canonical = dns_resource_record_ref(answer->items[i].rr);
219
220 added++;
221 }
222
223 // what about the cache?
224
225 /* If we didn't find anything, then let's restart the
226 * query, this time with the cname */
227 if (added <= 0) {
228 r = dns_query_go(q);
229 if (r < 0) {
230 r = sd_bus_reply_method_errno(q->request, -r, NULL);
231 goto finish;
232 }
233
234 return;
235 }
236 }
237
238 r = sd_bus_message_close_container(reply);
239 if (r < 0)
240 goto finish;
241
242 /* Return the precise spelling and uppercasing reported by the server */
243 assert(canonical);
244 r = sd_bus_message_append(reply, "st", DNS_RESOURCE_KEY_NAME(canonical->key), SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
245 if (r < 0)
246 goto finish;
247
248 r = sd_bus_send(q->manager->bus, reply, NULL);
249
250 finish:
251 if (r < 0) {
252 log_error_errno(r, "Failed to send hostname reply: %m");
253 sd_bus_reply_method_errno(q->request, -r, NULL);
254 }
255
256 dns_query_free(q);
257 }
258
259 static int check_ifindex_flags(int ifindex, uint64_t *flags, sd_bus_error *error) {
260 assert(flags);
261
262 if (ifindex < 0)
263 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
264
265 if (*flags & ~SD_RESOLVED_FLAGS_ALL)
266 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
267
268 if (*flags == 0)
269 *flags = SD_RESOLVED_FLAGS_DEFAULT;
270
271 return 0;
272 }
273
274 static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) {
275 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
276 Manager *m = userdata;
277 const char *hostname;
278 int family, ifindex;
279 uint64_t flags;
280 DnsQuery *q;
281 int r;
282
283 assert(message);
284 assert(m);
285
286 r = sd_bus_message_read(message, "isit", &ifindex, &hostname, &family, &flags);
287 if (r < 0)
288 return r;
289
290 if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
291 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
292
293 r = dns_name_normalize(hostname, NULL);
294 if (r < 0)
295 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
296
297 r = check_ifindex_flags(ifindex, &flags, error);
298 if (r < 0)
299 return r;
300
301 question = dns_question_new(family == AF_UNSPEC ? 2 : 1);
302 if (!question)
303 return -ENOMEM;
304
305 if (family != AF_INET6) {
306 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
307
308 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, hostname);
309 if (!key)
310 return -ENOMEM;
311
312 r = dns_question_add(question, key);
313 if (r < 0)
314 return r;
315 }
316
317 if (family != AF_INET) {
318 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
319
320 key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, hostname);
321 if (!key)
322 return -ENOMEM;
323
324 r = dns_question_add(question, key);
325 if (r < 0)
326 return r;
327 }
328
329 r = dns_query_new(m, &q, question, ifindex, flags);
330 if (r < 0)
331 return r;
332
333 q->request = sd_bus_message_ref(message);
334 q->request_family = family;
335 q->request_hostname = hostname;
336 q->complete = bus_method_resolve_hostname_complete;
337
338 r = dns_query_bus_track(q, message);
339 if (r < 0)
340 return r;
341
342 r = dns_query_go(q);
343 if (r < 0) {
344 dns_query_free(q);
345 return r;
346 }
347
348 return 1;
349 }
350
351 static void bus_method_resolve_address_complete(DnsQuery *q) {
352 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
353 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
354 unsigned added = 0, i;
355 int r;
356
357 assert(q);
358
359 if (q->state != DNS_TRANSACTION_SUCCESS) {
360 r = reply_query_state(q);
361 goto finish;
362 }
363
364 r = sd_bus_message_new_method_return(q->request, &reply);
365 if (r < 0)
366 goto finish;
367
368 r = sd_bus_message_open_container(reply, 'a', "(is)");
369 if (r < 0)
370 goto finish;
371
372 if (q->answer) {
373 answer = dns_answer_ref(q->answer);
374
375 for (i = 0; i < answer->n_rrs; i++) {
376 r = dns_question_matches_rr(q->question, answer->items[i].rr);
377 if (r < 0)
378 goto finish;
379 if (r == 0)
380 continue;
381
382 r = sd_bus_message_append(reply, "(is)", answer->items[i].ifindex, answer->items[i].rr->ptr.name);
383 if (r < 0)
384 goto finish;
385
386 added ++;
387 }
388 }
389
390 if (added == 0) {
391 _cleanup_free_ char *ip = NULL;
392
393 in_addr_to_string(q->request_family, &q->request_address, &ip);
394
395 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", ip);
396 goto finish;
397 }
398
399 r = sd_bus_message_close_container(reply);
400 if (r < 0)
401 goto finish;
402
403 r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
404 if (r < 0)
405 goto finish;
406
407 r = sd_bus_send(q->manager->bus, reply, NULL);
408
409 finish:
410 if (r < 0) {
411 log_error_errno(r, "Failed to send address reply: %m");
412 sd_bus_reply_method_errno(q->request, -r, NULL);
413 }
414
415 dns_query_free(q);
416 }
417
418 static int bus_method_resolve_address(sd_bus_message *message, void *userdata, sd_bus_error *error) {
419 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
420 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
421 _cleanup_free_ char *reverse = NULL;
422 Manager *m = userdata;
423 int family, ifindex;
424 uint64_t flags;
425 const void *d;
426 DnsQuery *q;
427 size_t sz;
428 int r;
429
430 assert(message);
431 assert(m);
432
433 r = sd_bus_message_read(message, "ii", &ifindex, &family);
434 if (r < 0)
435 return r;
436
437 if (!IN_SET(family, AF_INET, AF_INET6))
438 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
439
440 r = sd_bus_message_read_array(message, 'y', &d, &sz);
441 if (r < 0)
442 return r;
443
444 if (sz != FAMILY_ADDRESS_SIZE(family))
445 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
446
447 r = sd_bus_message_read(message, "t", &flags);
448 if (r < 0)
449 return r;
450
451 r = check_ifindex_flags(ifindex, &flags, error);
452 if (r < 0)
453 return r;
454
455 r = dns_name_reverse(family, d, &reverse);
456 if (r < 0)
457 return r;
458
459 question = dns_question_new(1);
460 if (!question)
461 return -ENOMEM;
462
463 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse);
464 if (!key)
465 return -ENOMEM;
466
467 reverse = NULL;
468
469 r = dns_question_add(question, key);
470 if (r < 0)
471 return r;
472
473 r = dns_query_new(m, &q, question, ifindex, flags);
474 if (r < 0)
475 return r;
476
477 q->request = sd_bus_message_ref(message);
478 q->request_family = family;
479 memcpy(&q->request_address, d, sz);
480 q->complete = bus_method_resolve_address_complete;
481
482 r = dns_query_bus_track(q, message);
483 if (r < 0)
484 return r;
485
486 r = dns_query_go(q);
487 if (r < 0) {
488 dns_query_free(q);
489 return r;
490 }
491
492 return 1;
493 }
494
495 static void bus_method_resolve_record_complete(DnsQuery *q) {
496 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
497 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
498 unsigned added = 0, i;
499 int r;
500
501 assert(q);
502
503 if (q->state != DNS_TRANSACTION_SUCCESS) {
504 r = reply_query_state(q);
505 goto finish;
506 }
507
508 r = sd_bus_message_new_method_return(q->request, &reply);
509 if (r < 0)
510 goto finish;
511
512 r = sd_bus_message_open_container(reply, 'a', "(iqqay)");
513 if (r < 0)
514 goto finish;
515
516 if (q->answer) {
517 answer = dns_answer_ref(q->answer);
518
519 for (i = 0; i < answer->n_rrs; i++) {
520 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
521 size_t start;
522
523 r = dns_question_matches_rr(q->question, answer->items[i].rr);
524 if (r < 0)
525 goto finish;
526 if (r == 0)
527 continue;
528
529 r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
530 if (r < 0)
531 goto finish;
532
533 p->refuse_compression = true;
534
535 r = dns_packet_append_rr(p, answer->items[i].rr, &start);
536 if (r < 0)
537 goto finish;
538
539 r = sd_bus_message_open_container(reply, 'r', "iqqay");
540 if (r < 0)
541 goto finish;
542
543 r = sd_bus_message_append(reply, "iqq",
544 answer->items[i].ifindex,
545 answer->items[i].rr->key->class,
546 answer->items[i].rr->key->type);
547 if (r < 0)
548 goto finish;
549
550 r = sd_bus_message_append_array(reply, 'y', DNS_PACKET_DATA(p) + start, p->size - start);
551 if (r < 0)
552 goto finish;
553
554 r = sd_bus_message_close_container(reply);
555 if (r < 0)
556 goto finish;
557
558 added ++;
559 }
560 }
561
562 if (added <= 0) {
563 r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Name '%s' does not have any RR of the requested type", q->request_hostname);
564 goto finish;
565 }
566
567 r = sd_bus_message_close_container(reply);
568 if (r < 0)
569 goto finish;
570
571 r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family));
572 if (r < 0)
573 goto finish;
574
575 r = sd_bus_send(q->manager->bus, reply, NULL);
576
577 finish:
578 if (r < 0) {
579 log_error_errno(r, "Failed to send record reply: %m");
580 sd_bus_reply_method_errno(q->request, -r, NULL);
581 }
582
583 dns_query_free(q);
584 }
585
586 static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd_bus_error *error) {
587 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
588 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
589 Manager *m = userdata;
590 uint16_t class, type;
591 const char *name;
592 int r, ifindex;
593 uint64_t flags;
594 DnsQuery *q;
595
596 assert(message);
597 assert(m);
598
599 r = sd_bus_message_read(message, "isqqt", &ifindex, &name, &class, &type, &flags);
600 if (r < 0)
601 return r;
602
603 r = dns_name_normalize(name, NULL);
604 if (r < 0)
605 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid name '%s'", name);
606
607 r = check_ifindex_flags(ifindex, &flags, error);
608 if (r < 0)
609 return r;
610
611 question = dns_question_new(1);
612 if (!question)
613 return -ENOMEM;
614
615 key = dns_resource_key_new(class, type, name);
616 if (!key)
617 return -ENOMEM;
618
619 r = dns_question_add(question, key);
620 if (r < 0)
621 return r;
622
623 r = dns_query_new(m, &q, question, ifindex, flags);
624 if (r < 0)
625 return r;
626
627 q->request = sd_bus_message_ref(message);
628 q->request_hostname = name;
629 q->complete = bus_method_resolve_record_complete;
630
631 r = dns_query_bus_track(q, message);
632 if (r < 0)
633 return r;
634
635 r = dns_query_go(q);
636 if (r < 0) {
637 dns_query_free(q);
638 return r;
639 }
640
641 return 1;
642 }
643
644 static const sd_bus_vtable resolve_vtable[] = {
645 SD_BUS_VTABLE_START(0),
646 SD_BUS_METHOD("ResolveHostname", "isit", "a(iiay)st", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
647 SD_BUS_METHOD("ResolveAddress", "iiayt", "a(is)t", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
648 SD_BUS_METHOD("ResolveRecord", "isqqt", "a(iqqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED),
649 SD_BUS_VTABLE_END,
650 };
651
652 static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
653 Manager *m = userdata;
654
655 assert(s);
656 assert(m);
657
658 m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
659
660 manager_connect_bus(m);
661 return 0;
662 }
663
664 static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
665 Manager *m = userdata;
666 int b, r;
667
668 assert(message);
669 assert(m);
670
671 r = sd_bus_message_read(message, "b", &b);
672 if (r < 0) {
673 log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
674 return 0;
675 }
676
677 if (b)
678 return 0;
679
680 log_debug("Coming back from suspend, verifying all RRs...");
681
682 manager_verify_all(m);
683 return 0;
684 }
685
686 int manager_connect_bus(Manager *m) {
687 int r;
688
689 assert(m);
690
691 if (m->bus)
692 return 0;
693
694 r = sd_bus_default_system(&m->bus);
695 if (r < 0) {
696 /* We failed to connect? Yuck, we must be in early
697 * boot. Let's try in 5s again. As soon as we have
698 * kdbus we can stop doing this... */
699
700 log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
701
702 r = sd_event_add_time(m->event, &m->bus_retry_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 5*USEC_PER_SEC, 0, on_bus_retry, m);
703 if (r < 0)
704 return log_error_errno(r, "Failed to install bus reconnect time event: %m");
705
706 return 0;
707 }
708
709 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
710 if (r < 0)
711 return log_error_errno(r, "Failed to register object: %m");
712
713 r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
714 if (r < 0)
715 return log_error_errno(r, "Failed to register name: %m");
716
717 r = sd_bus_attach_event(m->bus, m->event, 0);
718 if (r < 0)
719 return log_error_errno(r, "Failed to attach bus to event loop: %m");
720
721 r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
722 "type='signal',"
723 "sender='org.freedesktop.login1',"
724 "interface='org.freedesktop.login1.Manager',"
725 "member='PrepareForSleep',"
726 "path='/org/freedesktop/login1'",
727 match_prepare_for_sleep,
728 m);
729 if (r < 0)
730 log_error_errno(r, "Failed to add match for PrepareForSleep: %m");
731
732 return 0;
733 }