4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
43 #include <libzonecfg.h>
44 #include <sys/brand.h>
47 #define TZSYNC_FILE "/var/run/tzsync"
49 static void init_file(void);
50 static void doit(const char *zname
, const char *zroot
, int get
);
51 static void counter_get(const char *zname
, int fd
);
52 static void counter_set(int fd
);
53 static void walk_zones(int get
);
54 static void send_cron_msg(const char *zname
, const char *zroot
);
57 * There are undocumeted command line options:
58 * -l list the value of semaphore.
59 * -I initialize the semaphore file (ie /var/run/tzsync)
63 main(int argc
, char **argv
)
66 int all
= 0, get
= 0, init
= 0;
68 (void) setlocale(LC_ALL
, "");
69 (void) textdomain(TEXT_DOMAIN
);
71 while ((arg
= getopt(argc
, argv
, "alI")) != EOF
) {
83 (void) fprintf(stderr
,
84 gettext("Usage: tzreload [-a]\n"));
103 * Create /var/run/tzsync atomically.
105 * While creating the /var/run/tzsync initially, there is a timing window
106 * that the file is created but no disk block is allocated (empty file).
107 * If apps mmap'ed the file at the very moment, it succeeds but accessing
108 * the memory page causes a segfault since disk block isn't yet allocated.
109 * To avoid this situation, we create a temp file which has pagesize block
110 * assigned, and then rename it to tzsync.
115 char path
[sizeof (TZSYNC_FILE
) + 16];
120 /* We don't allow to re-create the file */
121 if (stat(TZSYNC_FILE
, &st
) == 0) {
122 (void) fprintf(stderr
, gettext("%s already exists.\n"),
127 pgsz
= sysconf(_SC_PAGESIZE
);
129 (void) strcpy(path
, TZSYNC_FILE
"XXXXXX");
130 if ((fd
= mkstemp(path
)) == -1) {
131 (void) fprintf(stderr
,
132 gettext("failed to create a temporary file.\n"));
136 if ((buf
= calloc(1, pgsz
)) == NULL
) {
137 (void) fprintf(stderr
, gettext("Insufficient memory.\n"));
144 if (write(fd
, buf
, pgsz
) != pgsz
) {
145 (void) fprintf(stderr
,
146 gettext("failed to create tzsync file, %s\n"),
153 if (link(path
, TZSYNC_FILE
) != 0) {
154 if (errno
== EEXIST
) {
155 (void) fprintf(stderr
, gettext("%s already exists.\n"),
158 (void) fprintf(stderr
, gettext("failed to create %s\n"),
167 * Unplivileged apps may fail to open the file until the chmod
168 * below succeeds. However, it's okay as long as open() fails;
169 * ctime() won't cache zoneinfo until file is opened and mmap'd.
172 /* /var/run/tzsync has been made. Adjust permission */
173 if (chmod(TZSYNC_FILE
, 0644) != 0) {
174 (void) fprintf(stderr
,
175 gettext("failed to change permission of %s\n"),
177 (void) unlink(TZSYNC_FILE
);
183 * Open the /var/run/tzsync, then set or get the semaphore.
185 * zname name of zone (NULL if no need to consider zones)
186 * zroot zone's root path
187 * get get/set semaphore
190 doit(const char *zname
, const char *zroot
, int get
)
193 char file
[PATH_MAX
+ 1];
195 if (strlcpy(file
, zroot
, sizeof (file
)) >= sizeof (file
) ||
196 strlcat(file
, TZSYNC_FILE
, sizeof (file
)) >= sizeof (file
)) {
197 (void) fprintf(stderr
, gettext("zonepath too long\n"));
201 if ((fd
= open(file
, get
? O_RDONLY
: O_RDWR
)) < 0) {
202 (void) fprintf(stderr
,
203 gettext("Can't open file %s, %s\n"),
204 file
, strerror(errno
));
209 counter_get(zname
, fd
);
212 /* let cron reschedule events */
213 send_cron_msg(zname
, zroot
);
220 * Get semaphore value and print.
223 counter_get(const char *zname
, int fd
)
228 addr
= mmap(NULL
, sizeof (uint32_t), PROT_READ
, MAP_SHARED
, fd
, 0);
229 if (addr
== MAP_FAILED
) {
230 (void) fprintf(stderr
,
231 gettext("Error mapping semaphore: %s\n"),
235 counter
= *(uint32_t *)(uintptr_t)addr
;
237 (void) munmap(addr
, sizeof (uint32_t));
240 (void) printf("%u\n", counter
);
242 (void) printf("%-20s %u\n", zname
, counter
);
247 * Increment semaphore value.
254 addr
= mmap(NULL
, sizeof (uint32_t), PROT_READ
|PROT_WRITE
,
256 if (addr
== MAP_FAILED
) {
257 (void) fprintf(stderr
,
258 gettext("Error mapping semaphore: %s\n"),
264 atomic_add_32((uint32_t *)addr
, 1);
266 (void) munmap(addr
, sizeof (uint32_t));
270 * Walk through running zones and call doit() for each zones.
272 * Note: we call zone_get_rootpath() indirectly using dlopen().
273 * This is because tzreload resides under /sbin and needs to run
274 * without /usr (ie /usr/lib/libzonecfg.so.1). The reason tzreload
275 * being in /sbin is that tzreload -I may be called to create
276 * /var/run/tzsync before /usr is mounted. To do that zone_get_rootpath()
277 * isn't necessary. Therefore, libzonecfg is dlopen'd when required
278 * rather than having static linkage to it which would make tzreload
279 * unable to run without /usr.
285 uint_t ui
, nzents
, onzents
;
286 char zroot
[PATH_MAX
+ 1];
287 char zname
[ZONENAME_MAX
];
288 char zbrand
[MAXNAMELEN
];
289 static int (*get_zroot
)(char *, char *, size_t);
291 if (getzoneid() != GLOBAL_ZONEID
) {
292 (void) fprintf(stderr
, gettext("not in the global zone.\n"));
296 if (get_zroot
== NULL
) {
299 if ((hdl
= dlopen("libzonecfg.so.1", RTLD_NOW
)) == NULL
) {
300 (void) fprintf(stderr
,
301 gettext("unable to get zone configuration.\n"));
304 get_zroot
= (int (*)(char *, char *, size_t))
305 dlsym(hdl
, "zone_get_rootpath");
306 if (get_zroot
== NULL
) {
307 (void) fprintf(stderr
,
308 gettext("unable to get zone configuration.\n"));
314 if (zone_list(NULL
, &nzents
) != 0) {
315 (void) fprintf(stderr
,
316 gettext("failed to get zoneid list\n"));
324 if ((zids
= malloc(nzents
* sizeof (zoneid_t
))) == NULL
) {
325 (void) fprintf(stderr
, gettext("Insufficient memory.\n"));
330 if (zone_list(zids
, &nzents
) != 0) {
331 (void) fprintf(stderr
,
332 gettext("failed to get zoneid list\n"));
336 if (nzents
!= onzents
) {
337 /* zone increased while doing zone_list() */
342 for (ui
= 0; ui
< nzents
; ui
++) {
343 if (zone_getattr(zids
[ui
], ZONE_ATTR_BRAND
, zbrand
,
344 sizeof (zbrand
)) < 0) {
345 (void) fprintf(stderr
,
346 gettext("failed to get zone attribute\n"));
349 /* We only take care of native zones */
350 if (strcmp(zbrand
, NATIVE_BRAND_NAME
) != 0)
352 if (getzonenamebyid(zids
[ui
], zname
, sizeof (zname
)) < 0) {
353 (void) fprintf(stderr
,
354 gettext("failed to get zone name\n"));
358 if (zids
[ui
] == GLOBAL_ZONEID
) {
361 if ((*get_zroot
)(zname
, zroot
,
362 sizeof (zroot
)) != Z_OK
) {
363 (void) fprintf(stderr
,
364 gettext("failed to get zone's root\n"));
368 doit(zname
, zroot
, get
);
375 * Send REFRESH event to cron.
378 send_cron_msg(const char *zname
, const char *zroot
)
382 char fifo
[PATH_MAX
+ 1];
384 if (strlcpy(fifo
, zroot
, sizeof (fifo
)) >= sizeof (fifo
) ||
385 strlcat(fifo
, FIFO
, sizeof (fifo
)) >= sizeof (fifo
)) {
386 (void) fprintf(stderr
, gettext("zonepath too long\n"));
390 (void) memset(&msg
, 0, sizeof (msg
));
393 if ((msgfd
= open(fifo
, O_WRONLY
|O_NDELAY
)) < 0) {
394 if (errno
== ENXIO
|| errno
== ENOENT
) {
396 (void) fprintf(stderr
, gettext(
397 "cron isn't running in %s zone.\n"), zname
);
399 (void) fprintf(stderr
,
400 gettext("cron isn't running.\n"));
404 (void) fprintf(stderr
, gettext(
405 "failed to send message to cron "
406 "in %s zone.\n"), zname
);
408 (void) fprintf(stderr
, gettext(
409 "failed to send message to cron.\n"));
415 if (write(msgfd
, &msg
, sizeof (msg
)) != sizeof (msg
)) {
416 (void) fprintf(stderr
, gettext("failed to send message.\n"));