xref: /netbsd/distrib/cdrom/Makefile (revision ed15fbcc)
1# $NetBSD: Makefile,v 1.53 2023/05/19 14:47:16 hauke Exp $
2#
3# Consult "*.conf" for the configuration variables; this Makefile is typically
4# not edited for basic configuration changes.
5##############################################################################
6
7all:	cdimages
8
9.include <bsd.own.mk>
10
11.if exists(site.conf)
12.include "site.conf"
13.endif
14
15.if ${MKREPRO_TIMESTAMP:Uno} != "no"
16PAX_TIMESTAMP=--timestamp "${MKREPRO_TIMESTAMP}"
17.endif
18
19.if !defined(RELEASE)
20.BEGIN:
21	@echo "Please set RELEASE in the environment or in site.conf to the basename"
22	@echo "of the release configuration file to use.  For example:"
23	@echo "> ${MAKE} RELEASE=foo"
24	@echo "will use the configuration file foo.conf."
25	@false
26.endif
27
28.if exists(${RELEASE}.conf)
29.include "${RELEASE}.conf"
30.elif !target(.BEGIN)
31.BEGIN:
32	@echo "Error: File does not exist: ${RELEASE}.conf"
33	@false
34.endif
35
36CD_RELEASE?=
37CD_SIZE?=		650000
38RELEASENAME?=		NetBSD-${CD_RELEASE}
39MKISOFS_ARGS=		-A "NetBSD ${CD_RELEASE}" \
40			-hide-rr-moved -m Split -m cdrom
41#			-hide-list ${.CURDIR}/hide-iso.lst
42
43ALL_PORTS=
44.for image in ${CD_IMAGES}
45BASE_PORTS.${image}?=
46ALL_PORTS:=		${ALL_PORTS} ${BASE_PORTS.${image}}
47.endfor
48
49.if exists(${RELEASENAME}.mk)
50.include "${RELEASENAME}.mk"
51.elif !target(.BEGIN)
52.if !empty(CD_RELEASE)
53.BEGIN:
54	@echo "Error: File does not exist: ${RELEASENAME}.mk"
55	@echo "(specified by variable CD_RELEASE in ${RELEASE}.conf)"
56	@false
57.else
58.BEGIN:
59	@echo "Error: CD_RELEASE not set in ${RELEASE}.conf"
60	@false
61.endif
62.endif
63
64SUBDIR=
65
66.if !empty(ALL_PORTS:Mmacppc)
67SUBDIR+=	macppc_installboot
68.endif
69
70.if !empty(SUBDIR)
71.include <bsd.subdir.mk>
72.endif
73
74.include <bsd.obj.mk>
75.include <bsd.own.mk>
76
77##### Default paths for programs #####
78
79MKISOFS?=	/usr/local/bin/mkisofs
80RSYNC?=		/usr/pkg/bin/rsync
81ALPHA_IBOOT?=	${TOOL_INSTALLBOOT} -m alpha -o sunsum,append
82PMAX_IBOOT?=	${TOOL_INSTALLBOOT} -m pmax -o sunsum,append
83VAX_IBOOT?=	${TOOL_INSTALLBOOT} -m vax -o sunsum,append
84.if !empty(ALL_PORTS:Mmacppc)
85MACPPC_IBOOTDIR!= cd ${.CURDIR}/macppc_installboot && ${PRINTOBJDIR}
86.endif
87.if !empty(ALL_PORTS:Msgimips)
88SGIMIPS_SGIVOL?=	${TOOLDIR}/bin/nbsgivol
89.endif
90
91check_mkisofs:
92.if !exists(${MKISOFS})
93	@echo "Error: File does not exist: ${MKISOFS}"
94	@echo "Please build and install mkisofs(8) utility and set MKISOFS in the environment"
95	@echo "or in site.conf to create image."
96	@false
97.endif
98
99check_rsync:
100.if !exists(${RSYNC})
101	@echo "Error: File does not exist: ${RSYNC}"
102	@echo "Please build and install rsync(1) utility and set RSYNC in the environment"
103	@echo "or in site.conf to fetch release binaries."
104	@false
105.endif
106
107##### rsync settings #####
108
109# rsync host; check mirrors on http://www.NetBSD.org/mirrors/#rsync
110# (note not all rsync mirrors provide NetBSD-daily)
111RSYNC_HOST?=	rsync.NetBSD.org
112
113# extra path for rsync mirrors ("/pub", "/netbsd" etc.)
114RSYNC_PATH_PREFIX?=
115
116.if !target(.BEGIN)
117.if ${RELEASE} == "current"
118# daily date dir name
119BRANCH?=	HEAD
120#DAILY_DIR?=	yyyymmddhhmmZ
121RSYNC_PATH?=	${RSYNC_PATH_PREFIX}/NetBSD-daily/${BRANCH}/${DAILY_DIR}
122.else
123# extra suffix on pre-release ("_BETA2", "_RC5" etc.)
124RELEASE_SUFFIX?=
125RSYNC_PATH?=	${RSYNC_PATH_PREFIX}/NetBSD/${RELEASENAME}${RELEASE_SUFFIX}
126
127# alternative for NetBSD-daily sets of stable branches
128#DAILY_DIR?=	yyyymmddhhmmZ
129#BRANCH?=	netbsd-4
130#RSYNC_PATH?=	${RSYNC_PATH_PREFIX}/NetBSD-daily/${BRANCH}/${DAILY_DIR}
131.endif
132.endif
133
134RSYNC_SITE?=	rsync://${RSYNC_HOST}${RSYNC_PATH}
135RSYNC_ARGS?=	-va --delete
136RSYNC_EXCLUDE+=	--exclude=/* --exclude=Split --exclude=cdrom
137
138DOWNLOADDIR?=	${.OBJDIR}/download
139DISTRIBDIR?=	${DOWNLOADDIR}
140STAGEDIR?=	${.OBJDIR}/staging
141IMAGEDIR?=	${.OBJDIR}
142EXTFILEDIR?=	${.OBJDIR}/extfiles
143EASTER_EGG?=	/dev/null
144
145##### MACHINE_ARCH for possible shared sets for each (shared) port #####
146
147MACHINE_ARCH.acorn32=	arm
148MACHINE_ARCH.algor=	mipsel
149MACHINE_ARCH.amiga=	m68k
150MACHINE_ARCH.amigappc=	powerpc
151MACHINE_ARCH.arc=	mipsel
152MACHINE_ARCH.atari=	m68k
153MACHINE_ARCH.bebox=	powerpc
154MACHINE_ARCH.cats=	arm
155MACHINE_ARCH.cesfic=	m68k
156MACHINE_ARCH.cobalt=	mipsel
157MACHINE_ARCH.dreamcast=	sh3el
158MACHINE_ARCH.evbarm=	arm
159MACHINE_ARCH.evbmips=	mipsel
160MACHINE_ARCH.evbppc=	powerpc
161MACHINE_ARCH.evbsh3=	sh3eb
162MACHINE_ARCH.hp300=	m68k
163MACHINE_ARCH.hpcarm=	arm
164MACHINE_ARCH.hpcmips=	mipsel
165MACHINE_ARCH.hpcsh=	sh3el
166MACHINE_ARCH.iyonix=	arm
167MACHINE_ARCH.luna68k=	m68k
168MACHINE_ARCH.mac68k=	m68k
169MACHINE_ARCH.macppc=	powerpc
170MACHINE_ARCH.mipsco=	mipseb
171MACHINE_ARCH.mmeye=	sh3eb
172MACHINE_ARCH.mvme68k=	m68k
173MACHINE_ARCH.netwinder=	arm
174MACHINE_ARCH.news68k=	m68k
175MACHINE_ARCH.newsmips=	mipseb
176MACHINE_ARCH.next68k=	m68k
177MACHINE_ARCH.ofppc=	powerpc
178MACHINE_ARCH.playstation2=mipsel
179MACHINE_ARCH.pmax=	mipsel
180MACHINE_ARCH.prep=	powerpc
181MACHINE_ARCH.sandpoint=	powerpc
182MACHINE_ARCH.sbmips=	mipseb
183MACHINE_ARCH.sgimips=	mipseb
184MACHINE_ARCH.shark=	arm
185MACHINE_ARCH.sun3=	m68k
186MACHINE_ARCH.x68k=	m68k
187
188##### Fetched directories from FTP server #####
189
190.if defined(ALL_PORTS) && !empty(ALL_PORTS)
191RSYNC_INCLUDE+=		--include "/shared"
192RSYNC_EXCLUDE+=		--exclude "/[a-z]*" \
193			--exclude "/shared/[a-z]*"
194.endif
195
196RSYNC_ARCHS=
197.for port in ${ALL_PORTS:O:u}			# {
198RSYNC_INCLUDE+=		--include "/${port}"
199.if defined(MACHINE_ARCH.${port})
200RSYNC_ARCHS+=		${MACHINE_ARCH.${port}}
201.endif
202.endfor						# }
203.for arch in ${RSYNC_ARCHS:O:u}
204RSYNC_INCLUDE+=		--include "/shared/${arch}"
205.endfor
206
207##### Boot info and additional options for various platforms #####
208
209.if defined(PUBLISHER)
210MKISOFS_ARGS+=		-publisher "${PUBLISHER}"
211.endif
212
213.if defined(PREPARER)
214MKISOFS_ARGS+=		-p "${PREPARER}"
215.endif
216
217
218##### Per image settings #####
219
220.for image in ${CD_IMAGES}			# {
221ports:=${BASE_PORTS.${image}}
222
223.if !defined(VOLID.${image}) && !target(.BEGIN)
224.BEGIN:
225	@echo "Error: VOLID.${image} not set in ${RELEASE}.conf"
226	@false
227.endif
228
229MKISOFS_ARGS.${image}=	-V "${VOLID.${image}}"
230
231pathlist.${image}:=${STAGEDIR}/${image}.pathlist
232contents.${image}:=${IMAGEDIR}/${image}.contents
233
234MKISOFS_ARGS.${image}+=	-graft-points -path-list ${pathlist.${image}}
235
236.if defined(ABSTRACT.${image})
237MKISOFS_ARGS.${image}+=	-abstract ${ABSTRACT.${image}}
238.endif
239
240# Options specified in release config file
241
242EXTFILES?=
243INTFILES.${image}?=
244INTDIRS.${image}?=
245ADDFILES.${image}?=
246
247bports=			# empty first
248# For a source only cd just ignore the shared/ALL directory
249.if ${ports} != "source" && exists(${DISTRIBDIR}/shared/ALL)
250bports+=		shared/ALL
251.endif
252.for port in ${ports}					# {
253EXTFILES+=		${EXTFILES.${port}}
254INTFILES.${image}+=	${INTFILES.${port}}
255INTDIRS.${image}+=	${INTDIRS.${port}}
256ADDFILES.${image}+=	${ADDFILES.${port}}
257MKISOFS_ARGS.${image}+=	${MKISOFS_ARGS.${port}}
258# add shared/ALL and shared/${MACHINE_ARCH} to BASE_PORTS.${image}
259bports+=		${port}
260.if defined(MACHINE_ARCH.${port}) &&	\
261    exists(${DISTRIBDIR}/shared/${MACHINE_ARCH.${port}})
262bports+=		shared/${MACHINE_ARCH.${port}}
263.endif
264.endfor							# }
265BASE_PORTS.${image}:=	${bports:O:u}
266
267
268# i386
269
270.if !empty(ports:Mi386)
271.if empty(INTFILES.i386:Mbootxx_cd9660)
272# non-emulation boot
273MKISOFS_ARGS.${image}+=	-b ${BOOTFILE.i386} -c boot.catalog -no-emul-boot
274.else
275#2.88MB emulation boot
276MKISOFS_ARGS.${image}+=	-b ${BOOTFILE.i386} -c boot.catalog
277.endif
278.endif
279
280# amd64
281
282.if !empty(ports:Mamd64)
283.if empty(INTFILES.amd64:Mbootxx_cd9660)
284# non-emulation boot
285MKISOFS_ARGS.${image}+=	-b ${BOOTFILE.amd64} -c boot.catalog -no-emul-boot
286.else
287#2.88MB emulation boot
288MKISOFS_ARGS.${image}+= -b ${BOOTFILE.amd64} -c boot.catalog
289.endif
290.endif
291
292# Mac (mac68k, macppc)
293
294.if !empty(ports:Mmacppc)
295BOOTHFS=	boothfs
296MKISOFS_ARGS.${image}+=	-hfs -part -hide-hfs-list ${.CURDIR}/hide-hfs.lst \
297	--macbin -map ${.CURDIR}/hfsmap.lst \
298	-boot-hfs-file ${.OBJDIR}/${BOOTHFS}
299UUDECODE_FILES=	${BOOTHFS}
300.include <bsd.files.mk>
301.elif defined(USE_APPLE_ISO) || !empty(ports:Mmac68k)
302MKISOFS_ARGS.${image}+=	-apple --macbin -data-change-warn -map ${.CURDIR}/hfsmap.lst
303.endif
304
305# Sun (sparc, sparc64, sun3)
306
307SUN_BOOT_ARGS.${image}:=
308.if !empty(ports:Msparc*) || !empty(ports:Msun3*)	# {
309SUN_BOOT.123:=	-
310SUN_BOOT.4:=	-
311SUN_BOOT.5:=	-
312
313.if !empty(ports:Msparc)
314SUN_BOOT.123:=	${BOOTFILE.sparc}
315.endif
316
317.if !empty(ports:Msun3)					# {
318.if !defined(BOOTFILE.sun3x)
319# NetBSD >= 1.4; sun3 and sun3x are the same
320SUN_BOOT.5:=	${BOOTFILE.sun3}
321.endif
322SUN_BOOT.4:=	${BOOTFILE.sun3}
323.endif							# }
324
325.if !empty(ports:Msun3x) && defined(BOOTFILE.sun3x)
326# NetBSD < 1.4; sun3 and sun3x are separate
327SUN_BOOT.5:=	${BOOTFILE.sun3x}
328.endif
329
330.if !empty(ports:Msparc64)				# {
331.if (${SUN_BOOT.5} != "-")
332# add warning
333SUN_BOOT.5:=	${SUN_BOOT.5} ${BOOTFILE.sparc64}
334.else
335SUN_BOOT.5:=	${BOOTFILE.sparc64}
336.endif
337.endif							# }
338
339SUN_BOOT_ARGS.${image}:= ${SUN_BOOT.123} ${SUN_BOOT.123} ${SUN_BOOT.123} ${SUN_BOOT.4} ${SUN_BOOT.5}
340
341.if empty(SUN_BOOT_ARGS.${image}:N/dev/null)
342SUN_BOOT_ARGS.${image}:=
343.endif
344.endif							# }
345
346.endfor		# image in ${CD_IMAGES}		# }
347
348##### Additional options for host OS's #####
349
350# (USE_APPLE_ISO is tested above)
351
352.if defined(USE_ROCK_RIDGE)
353MKISOFS_ARGS+=		-r
354.endif
355
356.if defined(USE_LONG_NAMES)
357MKISOFS_ARGS+=		-l
358.endif
359
360.if defined(USE_TRANS_TBL)
361MKISOFS_ARGS+=		-T
362.endif
363
364.if defined(USE_JOLIET)
365MKISOFS_ARGS+=		-J -hide-joliet-list ${.CURDIR}/hide-jol.lst
366.if defined(USE_TRANS_TBL)
367MKISOFS_ARGS+=		-hide-joliet-trans-tbl
368.endif
369.endif
370
371##### File extract rule #####
372
373USE-FILE: .USE
374	@if [ ! -r $@ ]; then case $> in \
375		/*,link) \
376			echo "cp ${>:S/,link$//} $@"; \
377			cp ${>:S/,link$//} $@;; \
378		*,link) \
379			echo "cp `pwd -P`/${>:S/,link$//} $@"; \
380			cp `pwd -P`/${>:S/,link$//} $@;; \
381		*.tgz,*) \
382			echo "Extracting: $> --> $@..."; \
383			${TOOL_PAX} ${PAX_TIMESTAMP} -rnz \
384			-f ${>:C/,.*$//} ${>:C/^.*,//} ; \
385			cp ${>:C/^.*,//} $@; rm -rf ${>:C/^.*,//} ;; \
386		*.gz) echo "gunzip -c <$> >$@"; gunzip -c <$> >$@;; \
387		*) echo "Unknown archive method for $@"; false;; \
388	esac; else true; fi
389
390##### Makefile rules #####
391
392.for image in ${CD_IMAGES}			# {
393cdimages: ${IMAGEDIR}/${image}.iso
394
395stage-${image}:
396	mkdir -p ${STAGEDIR}/${image} ${EXTFILEDIR}
397	rm -f ${pathlist.${image}} ${contents.${image}}
398.if defined(BASE_PORTS.${image}) && !empty(BASE_PORTS.${image})
399.for dir in ${INTDIRS.${image}}
400	mkdir -p ${STAGEDIR}/${image}/${dir}
401.endfor
402.for arch in ${BASE_PORTS.${image}}
403	@echo "${arch}=${DISTRIBDIR}/${arch}" >> ${pathlist.${image}}
404	@echo "${arch}" >> ${contents.${image}}
405.endfor
406.endif
407
408extfileprep:
409.for file in ${EXTFILES}			# {
410extfileprep: ${EXTFILEDIR}/${file:C/:.*$//}
411${EXTFILEDIR}/${file:C/:.*$//}: ${DISTRIBDIR}/${file:C/^.*://} USE-FILE
412${DISTRIBDIR}/${file:C/^.*://}: .PHONY
413.endfor						# }
414
415fileprep-${image}:
416.for file in ${INTFILES.${image}}		# {
417fileprep-${image}: ${STAGEDIR}/${image}/${file:C/:.*$//}
418${STAGEDIR}/${image}/${file:C/:.*$//}: ${DISTRIBDIR}/${file:C/^.*://} USE-FILE
419${DISTRIBDIR}/${file:C/^.*://}: .PHONY
420.endfor						# }
421.for file in ${ADDFILES.${image}}		# {
422fileprep-${image}: ${STAGEDIR}/${image}/${file:C/:.*$//}
423${STAGEDIR}/${image}/${file:C/:.*$//}: ${file:C/^.*://} USE-FILE
424${file:C/^.*://}: .PHONY
425.endfor						# }
426
427.if !empty(BASE_PORTS.${image}:Mmacppc)
428fileprep-${image}: ${BOOTHFS}
429.endif
430
431# Size the CD image.  This is done via the following formula:
432# 1. Size the image produced by mkisofs.
433# 2. Add images added by distrib/common/sunbootcd.sh by rounding to a 320k
434#    boundary and adding each Sun image rounded to a 320k boundary.
435# 3. Add bootfile sizes rounded up to 512 bytes for pmax and vax.
436# 4. Round up to a 32k boundary, then add another 32k for TAO padding.
437
438SGIVOLHDR.size= 4096
439
440size-${image}: stage-${image} extfileprep fileprep-${image} check_mkisofs
441	@size=$$((`cd ${STAGEDIR}/${image} && \
442		   ${MKISOFS} ${MKISOFS_ARGS} ${MKISOFS_ARGS.${image}} \
443			-print-size . 2>&1 \
444		   | tee /dev/stderr \
445		   | ${TOOL_SED} '/=/!d;s/^[^=]*=//'` * 2048)) && \
446	if [ "${SUN_BOOT_ARGS.${image}}" != "" ]; then \
447		size=$$(($$(($$size + 327679)) / 327680 * 327680)) && \
448		bootfiles=`for f in ${SUN_BOOT_ARGS.${image}:N-:O}; do echo $$f; done | uniq` && \
449		for f in $$bootfiles; do \
450			bfsize=$$(${TOOL_STAT} -f '%z' $$f) && \
451			size=$$(($$size + $$(($$(($$bfsize + 327679)) / 327680 * 327680)))); \
452		done; \
453	fi && \
454	if [ "${BASE_PORTS.${image}:Mpmax}" != "" ]; then \
455		size=$$(($$size + $$(($$(($$(${TOOL_STAT} -f '%z' ${BOOTFILE.pmax}) + 511)) / 512 * 512)))); \
456	fi && \
457	if [ "${BASE_PORTS.${image}:Mvax}" != "" ]; then \
458		size=$$(($$size + $$(($$(($$(${TOOL_STAT} -f '%z' ${BOOTFILE.vax})  + 511)) / 512 * 512)))); \
459	fi && \
460	if [ "${BASE_PORTS.${image}:Msgimips}" != "" -a \
461	    "${EXTFILES.sgimips}" != "" ]; then \
462		size=$$(($$size + ${SGIVOLHDR.size} * 512)); \
463	fi && \
464	size=$$(($$(($$size + 16383)) / 16384 * 16384 + 32768)) && \
465	sizek=$$(($$size / 1024)) && \
466	echo "Projected size of ${image}.iso: $$size bytes ($${sizek}K)." && \
467	if [ $$sizek -gt ${CD_SIZE} ]; then echo "Image too large for ${CD_SIZE} KB CD!"; false; fi
468
469# Actually build the image with all the bootstrap goo....
470
471.if !empty(BASE_PORTS.${image}:Mmacppc)
472${IMAGEDIR}/${image}.iso: all-macppc_installboot
473.endif
474
475${IMAGEDIR}/${image}.iso: size-${image} check_mkisofs
476	@sort -o ${contents.${image}} ${contents.${image}}
477.if defined(LOG_MKISOFS)
478	cd ${STAGEDIR}/${image} && ${MKISOFS} -o $@ ${MKISOFS_ARGS} ${MKISOFS_ARGS.${image}} -v -v . >${IMAGEDIR}/${image}.iso.log 2>&1
479.else
480	cd ${STAGEDIR}/${image} && ${MKISOFS} -o $@ ${MKISOFS_ARGS} ${MKISOFS_ARGS.${image}} .
481.endif
482.if !empty(SUN_BOOT_ARGS.${image})
483	SUNLABEL=${TOOL_SUNLABEL:Q} \
484	    ${HOST_SH} ${NETBSDSRCDIR}/distrib/common/sunbootcd.sh \
485	    ${.TARGET} ${SUN_BOOT_ARGS.${image}}
486.endif
487.if !empty(BASE_PORTS.${image}:Mmacppc)
488	${MACPPC_IBOOTDIR}/macppc_installboot \
489	    $@ ${EXTFILEDIR}/macppc.bootxx /ofwboot
490.endif
491.if !empty(BASE_PORTS.${image}:Mpmax)
492	${PMAX_IBOOT} $@ ${BOOTFILE.pmax}
493.endif
494.if !empty(BASE_PORTS.${image}:Mvax)
495	${VAX_IBOOT} $@ ${BOOTFILE.vax}
496.endif
497.if !empty(BASE_PORTS.${image}:Malpha)
498	${ALPHA_IBOOT} $@ ${BOOTFILE.alpha}
499.endif
500.if !empty(BASE_PORTS.${image}:Msgimips) && defined(EXTFILES.sgimips)
501	@echo "Prepending SGI volume header"
502	mv $@ $@.raw
503	dd if=/dev/zero of=$@.tmp bs=512 count=${SGIVOLHDR.size}
504	dd if=$@.raw of=$@.tmp bs=512 seek=${SGIVOLHDR.size}
505	${SGIMIPS_SGIVOL} -f -i -h ${SGIVOLHDR.size} $@.tmp
506	${SGIMIPS_SGIVOL} -f -w aoutboot ${STAGEDIR}/${image}/aoutboot $@.tmp
507	${SGIMIPS_SGIVOL} -f -w ip2xboot ${STAGEDIR}/${image}/ip2xboot $@.tmp
508	${SGIMIPS_SGIVOL} -f -w ip3xboot ${STAGEDIR}/${image}/ip3xboot $@.tmp
509	mv $@.tmp $@
510	rm -f $@.raw $@.tmp
511.endif
512	@echo Rounding up to 32k boundary and padding 32k....
513	@size=$$(${TOOL_STAT} -f '%z' $@); \
514	    pad=$$(( 32768 - ( $$size & 32767 ) )); \
515	    [ $$pad = 32768 ] || \
516	    dd if=/dev/zero bs=1 count=$$pad >>$@ 2>/dev/null
517
518.endfor		# image in ${CD_IMAGES}		# }
519
520fetch: check_rsync
521	@mkdir -p ${DISTRIBDIR}
522	@echo Fetching distributions....
523	${RSYNC} ${RSYNC_INCLUDE} ${RSYNC_ARGS} ${RSYNC_EXCLUDE} ${RSYNC_SITE}/ ${DISTRIBDIR}/
524
525clean: cleanstagedir cleanimages
526cleandir distclean: cleandownloaddir
527
528cleanimages:
529.for image in ${CD_IMAGES}
530	-rm -f ${IMAGEDIR}/${image}.iso ${IMAGEDIR}/${image}.iso.log \
531		${contents.${image}}
532.endfor
533
534cleanstagedir:
535	-rm -rf ${STAGEDIR} ${EXTFILEDIR}
536
537cleandownloaddir:
538	-rm -rf ${DOWNLOADDIR}
539